"automatic usertypes" are now applied everywhere, regardless of what happens

new sol::filters (currently undocumented)
new gc tests, new plain_type tests
core abstractions over usertypes streamlined
SOL_STRINGS_ARE_NUMBERS triggers added
update single
This commit is contained in:
ThePhD 2017-08-21 15:25:43 -04:00
parent 488edd9cd1
commit 0c9d567d0a
50 changed files with 3534 additions and 1856 deletions

View File

@ -121,6 +121,7 @@ Thanks to `Eric (EToreo) for the suggestion on this one`_!
sol::load_result load(lua_Reader reader, void* data, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_buffer(const char* buff, std::size_t buffsize, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_file(const std::string& filename, load_mode mode = load_mode::any);
These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. That blob will be turned into a Lua Function. It will not be run: it returns a ``load_result`` proxy that can be called to actually run the code, when you are ready. It can also be turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction that can serve to call the function. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider using :doc:`sol::environment<environment>`, creating a new state, or other Lua sandboxing techniques.

View File

@ -16,7 +16,14 @@ Note that you can obtain safety with regards to functions you bind by using the
``SOL_SAFE_FUNCTION`` triggers the following change:
* All uses of ``sol::function`` and ``sol::stack_function`` will default to ``sol::protected_function`` and ``sol::stack_protected_function``, respectively, rather than ``sol::unsafe_function`` and ``sol::stack_unsafe_function``.
* **Not** turned on by default under any detectible compiler settings: *you must turn this one on manually*
* **Not** turned on by default under any detectible compiler settings: *you MUST turn this one on manually*
``SOL_STRINGS_ARE_NUMBERS`` triggers the following changes:
* ``sol::stack::get`` and ``sol::stack::check_get`` will allow anything that Lua thinks is number-worthy to be number-worthy
* This includes: integers, numbers, and strings
* Does **not** include: booleans, types with ``__tostring`` enabled, and everything else
* Overrides ``SOL_CHECK_ARGUMENTS`` and always applies if it is turned on
* **Not** turned on by default under any settings: *you MUST be turned on manually*
``SOL_CHECK_ARGUMENTS`` triggers the following changes:
* ``sol::stack::get`` (used everywhere) defaults to using ``sol::stack::check_get`` and dereferencing the argument. It uses ``sol::type_panic`` as the handler if something goes wrong

File diff suppressed because it is too large Load Diff

View File

@ -25,14 +25,66 @@
#include "protect.hpp"
#include "wrapper.hpp"
#include "property.hpp"
#include "filters.hpp"
#include "stack.hpp"
namespace sol {
namespace usertype_detail {
} // usertype_detail
namespace filter_detail {
template <int I, int... In>
inline void handle_filter(static_stack_dependencies<I, In...>, lua_State* L, int&) {
if (sizeof...(In) == 0) {
return;
}
absolute_index ai(L, I);
if (type_of(L, ai) != type::userdata) {
return;
}
lua_createtable(L, static_cast<int>(sizeof...(In)), 0);
stack_reference deps(L, -1);
auto per_dep = [&L, &deps](int i) {
lua_pushvalue(L, i);
luaL_ref(L, deps.stack_index());
};
(void)per_dep;
(void)detail::swallow{ int(), (per_dep(In), int())... };
lua_setuservalue(L, ai);
}
template <int... In>
inline void handle_filter(returns_self_with<In...>, lua_State* L, int& pushed) {
pushed = stack::push(L, raw_index(1));
handle_filter(static_stack_dependencies<-1, In...>(), L, pushed);
}
inline void handle_filter(const stack_dependencies& sdeps, lua_State* L, int&) {
absolute_index ai(L, sdeps.target);
if (type_of(L, ai) != type::userdata) {
return;
}
lua_createtable(L, static_cast<int>(sdeps.size()), 0);
stack_reference deps(L, -1);
for (std::size_t i = 0; i < sdeps.size(); ++i) {
lua_pushvalue(L, sdeps.stack_indices[i]);
luaL_ref(L, deps.stack_index());
}
lua_setuservalue(L, ai);
}
template <typename P, meta::disable<std::is_base_of<detail::filter_base_tag, meta::unqualified_t<P>>> = meta::enabler>
inline void handle_filter(P&& p, lua_State* L, int& pushed) {
pushed = std::forward<P>(p)(L, pushed);
}
} // filter_detail
namespace function_detail {
inline int no_construction_error(lua_State* L) {
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
}
}
} // function_detail
namespace call_detail {
@ -54,7 +106,7 @@ namespace sol {
static void call(Args...) {}
};
template <typename T>
template <typename T, bool checked, bool clean_stack>
struct constructor_match {
T* obj;
@ -63,7 +115,7 @@ namespace sol {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
detail::default_construct func{};
return stack::call_into_lua<stack::stack_detail::default_check_arguments>(r, a, L, start, func, obj);
return stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, obj);
}
};
@ -149,7 +201,7 @@ namespace sol {
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename T, typename... TypeLists>
template <typename T, bool checked, bool clean_stack, typename... TypeLists>
inline int construct(lua_State* L) {
static const auto& meta = usertype_traits<T>::metatable();
int argcount = lua_gettop(L);
@ -163,7 +215,7 @@ namespace sol {
reference userdataref(L, -1);
userdataref.pop();
construct_match<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &meta[0]);
@ -176,7 +228,7 @@ namespace sol {
return 1;
}
template <typename F, bool is_index, bool is_variable, bool checked, int boost, typename = void>
template <typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename = void>
struct agnostic_lua_call_wrapper {
template <typename Fx, typename... Args>
static int call(lua_State* L, Fx&& f, Args&&... args) {
@ -184,23 +236,30 @@ namespace sol {
typedef typename wrap::returns_list returns_list;
typedef typename wrap::free_args_list args_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...);
return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...);
}
};
template <typename T, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, true, is_variable, checked, boost, C> {
template <typename T, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, true, is_variable, checked, boost, clean_stack, C> {
template <typename F>
static int call(lua_State* L, F&& f) {
typedef is_stack_based<meta::unqualified_t<decltype(detail::unwrap(f.value))>> is_stack;
if (clean_stack && !is_stack::value) {
lua_settop(L, 0);
}
return stack::push_reference(L, detail::unwrap(f.value));
}
};
template <typename T, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, C> {
template <typename T, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, clean_stack, C> {
template <typename V>
static int call_assign(std::true_type, lua_State* L, V&& f) {
detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1));
if (clean_stack) {
lua_settop(L, 0);
}
return 0;
}
@ -226,63 +285,63 @@ namespace sol {
}
};
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, C> {
template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, lua_r_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, C> {
template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, lua_CFunction f) {
return f(L);
}
};
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, C> {
template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, detail::lua_CFunction_noexcept f) {
return f(L);
}
};
#endif // noexcept function types
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, boost, C> {
template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, const no_prop&) {
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
}
};
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, C> {
template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, const no_construction&) {
return function_detail::no_construction_error(L);
}
};
template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, C> {
template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State*, const bases<Args...>&) {
// Uh. How did you even call this, lul
return 0;
}
};
template <typename T, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, C> {
template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, std::reference_wrapper<T> f) {
return agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost>{}.call(L, f.get());
return agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.get());
}
};
template <typename T, typename F, bool is_index, bool is_variable, bool checked = stack::stack_detail::default_check_arguments, int boost = 0, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost> {};
template <typename T, typename F, bool is_index, bool is_variable, bool checked = stack::stack_detail::default_check_arguments, int boost = 0, bool clean_stack = true, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> {};
template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost>
struct lua_call_wrapper<T, F, is_index, is_variable, checked, boost, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, F, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
@ -291,7 +350,7 @@ namespace sol {
typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<Fx>(f), o);
return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward<Fx>(f), o);
}
template <typename Fx>
@ -311,8 +370,8 @@ namespace sol {
}
};
template <typename T, typename F, bool is_variable, bool checked, int boost>
struct lua_call_wrapper<T, F, false, is_variable, checked, boost, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, F, false, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef lua_bind_traits<F> traits_type;
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
@ -321,7 +380,7 @@ namespace sol {
static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) {
typedef typename wrap::args_list args_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(types<void>(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
return stack::call_into_lua<checked, clean_stack>(types<void>(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
}
template <typename V>
@ -370,8 +429,8 @@ namespace sol {
}
};
template <typename T, typename F, bool is_variable, bool checked, int boost>
struct lua_call_wrapper<T, F, true, is_variable, checked, boost, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef lua_bind_traits<F> traits_type;
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
@ -381,7 +440,7 @@ namespace sol {
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
F f(std::forward<V>(v));
return stack::call_into_lua<checked>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
return stack::call_into_lua<checked, clean_stack>(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o);
}
template <typename V>
@ -404,8 +463,8 @@ namespace sol {
}
};
template <typename T, typename F, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, readonly_wrapper<F>, false, is_variable, checked, boost, C> {
template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, readonly_wrapper<F>, false, is_variable, checked, boost, clean_stack, C> {
typedef lua_bind_traits<F> traits_type;
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
@ -421,13 +480,13 @@ namespace sol {
}
};
template <typename T, typename F, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, readonly_wrapper<F>, true, is_variable, checked, boost, C> : lua_call_wrapper<T, F, true, is_variable, checked, boost, C> {
template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, readonly_wrapper<F>, true, is_variable, checked, boost, clean_stack, C> : lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> {
};
template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, C> {
template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef constructor_list<Args...> F;
static int call(lua_State* L, F&) {
@ -442,7 +501,7 @@ namespace sol {
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj;
construct_match<T, Args...>(constructor_match<T>(obj), L, argcount, boost + 1 + static_cast<int>(syntax));
construct_match<T, Args...>(constructor_match<T, false, clean_stack>(obj), L, argcount, boost + 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &metakey[0]);
@ -456,8 +515,8 @@ namespace sol {
}
};
template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, C> {
template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef constructor_wrapper<Cxs...> F;
struct onmatch {
@ -471,7 +530,7 @@ namespace sol {
referencepointer = obj;
auto& func = std::get<I>(f.functions);
stack::call_into_lua<checked>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj));
stack::call_into_lua<checked, clean_stack>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj));
userdataref.push();
luaL_getmetatable(L, &metakey[0]);
@ -496,17 +555,17 @@ namespace sol {
};
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost>
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, std::enable_if_t<std::is_void<Fx>::value>> {
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_void<Fx>::value>> {
typedef destructor_wrapper<Fx> F;
static int call(lua_State* L, const F&) {
return detail::usertype_alloc_destroy<T>(L);
return detail::usertype_alloc_destruct<T>(L);
}
};
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost>
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, std::enable_if_t<!std::is_void<Fx>::value>> {
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack>
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<!std::is_void<Fx>::value>> {
typedef destructor_wrapper<Fx> F;
static int call(lua_State* L, const F& f) {
@ -516,8 +575,8 @@ namespace sol {
}
};
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, C> {
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef overload_set<Fs...> F;
struct on_match {
@ -533,15 +592,15 @@ namespace sol {
}
};
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, C> {
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef factory_wrapper<Fs...> F;
struct on_match {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
auto& f = std::get<I>(fx.functions);
return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f);
return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f);
}
};
@ -550,8 +609,8 @@ namespace sol {
}
};
template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, C> {
template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef std::conditional_t<is_index, R, W> P;
typedef meta::unqualified_t<P> U;
typedef wrapper<U> wrap;
@ -564,7 +623,7 @@ namespace sol {
typedef typename traits_type::free_args_list args_list;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f);
return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f);
}
template <typename F>
@ -585,7 +644,7 @@ namespace sol {
#endif // Safety
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<checked>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o);
return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o);
}
template <typename F, typename... Args>
@ -596,7 +655,7 @@ namespace sol {
template <typename F, typename... Args>
static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) {
auto& p = pick(meta::boolean<is_index>(), std::forward<F>(f));
return lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost>{}.call(L, p, std::forward<Args>(args)...);
return lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, p, std::forward<Args>(args)...);
}
template <typename F, typename... Args>
@ -613,33 +672,50 @@ namespace sol {
}
};
template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, C> {
template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef protect_t<V> F;
template <typename... Args>
static int call(lua_State* L, F& fx, Args&&... args) {
return lua_call_wrapper<T, V, is_index, is_variable, true, boost>{}.call(L, fx.value, std::forward<Args>(args)...);
return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack>{}.call(L, fx.value, std::forward<Args>(args)...);
}
};
template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, C> {
template <typename T, typename F, typename... Filters, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, filter_wrapper<F, Filters...>, is_index, is_variable, checked, boost, clean_stack, C> {
typedef filter_wrapper<F, Filters...> P;
template <std::size_t... In>
static int call(std::index_sequence<In...>, lua_State* L, P& fx) {
int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C>{}.call(L, fx.value);
(void)detail::swallow{ int(), (filter_detail::handle_filter(std::get<In>(fx.filters), L, pushed), int())... };
return pushed;
}
static int call(lua_State* L, P& fx) {
typedef typename P::indices indices;
return call(indices(), L, fx);
}
};
template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> {
template <typename F>
static int call(lua_State* L, F&& f) {
return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.arguments));
return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::get<0>(f.arguments));
}
};
template <typename T, bool is_index, bool is_variable, int boost = 0, typename Fx, typename... Args>
template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = stack::stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... Args>
inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <typename T, bool is_index, bool is_variable, typename F, int start = 1>
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = stack::stack_detail::default_check_arguments, bool clean_stack = true>
inline int call_user(lua_State* L) {
auto& fx = stack::get<user<F>>(L, upvalue_index(start));
return call_wrapped<T, is_index, is_variable>(L, fx);
return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
}
template <typename T, typename = void>
@ -658,7 +734,10 @@ namespace sol {
struct is_var_bind<var_wrapper<T>> : std::true_type {};
template <typename T>
struct is_var_bind<readonly_wrapper<T>> : is_var_bind<T> {};
struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> {};
template <typename F, typename... Filters>
struct is_var_bind<filter_wrapper<F, Filters...>> : is_var_bind<meta::unqualified_t<F>> {};
} // call_detail
template <typename T>

View File

@ -276,7 +276,7 @@ namespace sol {
{ "add", &meta_cumt::add_call },
{ "find", &meta_cumt::find_call },
{ "erase", &meta_cumt::erase_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> },
{ nullptr, nullptr }
} };

View File

@ -88,8 +88,8 @@ namespace sol {
name.replace(0, 6, "", 0);
if (name.find("class", 0) == 0)
name.replace(0, 5, "", 0);
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin());
while (!name.empty() && std::isblank(name.back())) name.pop_back();
while (!name.empty() && isblank(name.front())) name.erase(name.begin());
while (!name.empty() && isblank(name.back())) name.pop_back();
for (std::size_t r = 0; r < removals.size(); ++r) {
auto found = name.find(removals[r]);

86
sol/filters.hpp Normal file
View File

@ -0,0 +1,86 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FILTERS_HPP
#define SOL_FILTERS_HPP
#include "traits.hpp"
#include <array>
namespace sol {
namespace detail {
struct filter_base_tag {};
} // detail
template <int Target, int... In>
struct static_stack_dependencies : detail::filter_base_tag {};
typedef static_stack_dependencies<-1, 1> self_dependency;
template <int... In>
struct returns_self_with : detail::filter_base_tag {};
typedef returns_self_with<> returns_self;
struct stack_dependencies : detail::filter_base_tag {
int target;
std::array<int, 64> stack_indices;
std::size_t len;
template <typename... Args>
stack_dependencies(int stack_target, Args&&... args) : target(stack_target), stack_indices(), len(sizeof...(Args)) {
std::size_t i = 0;
(void)detail::swallow{ int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int() )... };
}
int& operator[] (std::size_t i) {
return stack_indices[i];
}
const int& operator[] (std::size_t i) const {
return stack_indices[i];
}
std::size_t size() const {
return len;
}
};
template <typename F, typename... Filters>
struct filter_wrapper {
typedef std::make_integer_sequence<std::size_t, sizeof...(Filters)> indices;
F value;
std::tuple<Filters...> filters;
template <typename Fx, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Fx>, filter_wrapper>>> = meta::enabler>
filter_wrapper(Fx&& fx, Args&&... args) : value(std::forward<Fx>(fx)), filters(std::forward<Args>(args)...) {}
filter_wrapper(const filter_wrapper&) = default;
filter_wrapper& operator=(const filter_wrapper&) = default;
filter_wrapper(filter_wrapper&&) = default;
filter_wrapper& operator=(filter_wrapper&&) = default;
};
template <typename F, typename... Args>
auto filters(F&& f, Args&&... args) {
return filter_wrapper<std::decay_t<F>, std::decay_t<Args>...>( std::forward<F>(f), std::forward<Args>(args)... );
}
} // sol
#endif // SOL_FILTERS_HPP

View File

@ -110,7 +110,10 @@ namespace sol {
struct user;
template <typename T>
struct as_args_t;
template <typename T>
struct protect_t;
template <typename F, typename... Filters>
struct filter_wrapper;
} // sol
#endif // SOL_FORWARD_HPP

54
sol/forward_detail.hpp Normal file
View File

@ -0,0 +1,54 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FORWARD_DETAIL_HPP
#define SOL_FORWARD_DETAIL_HPP
#include "feature_test.hpp"
#include "forward.hpp"
#include "traits.hpp"
namespace sol {
namespace meta {
namespace meta_detail {
} // meta_detail
} // meta
namespace stack {
namespace stack_detail {
template <typename T>
struct undefined_metatable;
} // stack_detail
} // stack
namespace usertype_detail {
template <typename T, typename Regs, typename Fx>
void insert_default_registrations(Regs& l, int& index, Fx&& fx);
template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler>
void make_destructor(Regs& l, int& index);
template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler>
void make_destructor(Regs& l, int& index);
} // usertype_detail
} // sol
#endif // SOL_FORWARD_DETAIL_HPP

View File

@ -391,7 +391,7 @@ namespace sol {
template <typename T, typename... Lists>
struct pusher<detail::tagged<T, constructor_list<Lists...>>> {
static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) {
lua_CFunction cf = call_detail::construct<T, Lists...>;
lua_CFunction cf = call_detail::construct<T, stack_detail::default_check_arguments, true, Lists...>;
return stack::push(L, cf);
}
};
@ -411,7 +411,7 @@ namespace sol {
template <typename T>
struct pusher<detail::tagged<T, destructor_wrapper<void>>> {
static int push(lua_State* L, destructor_wrapper<void>) {
lua_CFunction cf = detail::usertype_alloc_destroy<T>;
lua_CFunction cf = detail::usertype_alloc_destruct<T>;
return stack::push(L, cf);
}
};
@ -427,6 +427,26 @@ namespace sol {
}
};
template <typename F, typename... Filters>
struct pusher<filter_wrapper<F, Filters...>> {
typedef filter_wrapper<F, Filters...> P;
static int push(lua_State* L, const P& p) {
lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<P>>(L, p);
return stack::push(L, c_closure(cf, upvalues));
}
static int push(lua_State* L, P&& p) {
lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<P>>(L, std::move(p));
return stack::push(L, c_closure(cf, upvalues));
}
};
} // stack
} // sol

View File

@ -43,6 +43,19 @@ namespace sol {
tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
}
auto setup_table(std::true_type) {
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, tbl.stack_index());
lua_pop(lua_state(), p.levels);
return p;
}
bool is_valid(std::false_type) {
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
lua_pop(lua_state(), p.levels);
return p;
}
public:
Table tbl;
key_type key;

View File

@ -22,9 +22,10 @@
#ifndef SOL_RAII_HPP
#define SOL_RAII_HPP
#include <memory>
#include "traits.hpp"
#include <memory>
namespace sol {
namespace detail {
struct default_construct {

View File

@ -69,17 +69,23 @@ namespace sol {
struct push_popper_n<true> {
push_popper_n(lua_State*, int) { }
};
template <bool top_level, typename T>
template <bool, typename T, typename = void>
struct push_popper {
T t;
push_popper(T x) : t(x) { t.push(); }
~push_popper() { t.pop(); }
};
template <typename T>
struct push_popper<true, T> {
template <typename T, typename C>
struct push_popper<true, T, C> {
push_popper(T) {}
~push_popper() {}
};
template <typename T>
struct push_popper<false, T, std::enable_if_t<std::is_base_of<stack_reference, meta::unqualified_t<T>>::value>> {
push_popper(T) {}
~push_popper() {}
};
template <bool top_level = false, typename T>
push_popper<top_level, T> push_pop(T&& x) {
return push_popper<top_level, T>(std::forward<T>(x));

View File

@ -322,7 +322,7 @@ namespace sol {
private:
template<std::size_t... I, typename Tuple>
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
simple_usertype_metatable(detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
: callconstructfunc(lua_nil),
indexfunc(lua_nil), newindexfunc(lua_nil),
indexbase(&usertype_detail::simple_core_indexing_call<T, true>), newindexbase(&usertype_detail::simple_core_indexing_call<T, false>),
@ -337,33 +337,33 @@ namespace sol {
}
template<typename... Args>
simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {}
simple_usertype_metatable(lua_State* L, detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) {}
template<typename... Args>
simple_usertype_metatable(lua_State* L, usertype_detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
simple_usertype_metatable(lua_State* L, detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
template<typename... Args>
simple_usertype_metatable(lua_State* L, usertype_detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward<Args>(args)...) {}
simple_usertype_metatable(lua_State* L, detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_destructible<T>, meta::neg<detail::has_destructor<Args...>>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward<Args>(args)...) {}
public:
simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>>, decltype(default_constructor), usertype_detail::check_destructor_tag>()) {}
simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>>, decltype(default_constructor), detail::check_destructor_tag>()) {}
template<typename Arg, typename... Args, meta::disable_any<
meta::any_same<meta::unqualified_t<Arg>,
usertype_detail::verified_tag,
usertype_detail::add_destructor_tag,
usertype_detail::check_destructor_tag
detail::verified_tag,
detail::add_destructor_tag,
detail::check_destructor_tag
>,
meta::is_specialization_of<constructors, meta::unqualified_t<Arg>>,
meta::is_specialization_of<constructor_wrapper, meta::unqualified_t<Arg>>
> = meta::enabler>
simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward<Arg>(arg), std::forward<Args>(args)...) {}
simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<detail::has_constructor<Args...>>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward<Arg>(arg), std::forward<Args>(args)...) {}
template<typename... Args, typename... CArgs>
simple_usertype_metatable(lua_State* L, constructors<CArgs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
simple_usertype_metatable(lua_State* L, constructors<CArgs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args, typename... Fxs>
simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
simple_usertype_metatable(const simple_usertype_metatable&) = default;
simple_usertype_metatable(simple_usertype_metatable&&) = default;
@ -420,18 +420,18 @@ namespace sol {
for (std::size_t i = 1; i < properties.size(); ++i) {
mf = static_cast<meta_function>(i);
const std::string& mfname = to_string(mf);
if (mfname == first) {
properties[i] = true;
switch (mf) {
case meta_function::index:
umx.indexfunc = second;
break;
case meta_function::new_index:
umx.newindexfunc = second;
break;
default:
break;
}
if (mfname != first)
continue;
properties[i] = true;
switch (mf) {
case meta_function::index:
umx.indexfunc = second;
break;
case meta_function::new_index:
umx.newindexfunc = second;
break;
default:
break;
}
break;
}
@ -474,34 +474,10 @@ namespace sol {
auto& second = std::get<1>(kvp);
register_kvp(i, t, first, second);
}
luaL_Reg opregs[29]{};
luaL_Reg opregs[32]{};
int opregsindex = 0;
if (!properties[static_cast<int>(meta_function::less_than)]) {
const char* name = to_string(meta_function::less_than).c_str();
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(opregs, opregsindex, name);
}
if (!properties[static_cast<int>(meta_function::less_than_or_equal_to)]) {
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(opregs, opregsindex, name);
}
if (!properties[static_cast<int>(meta_function::equal_to)]) {
const char* name = to_string(meta_function::equal_to).c_str();
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name);
}
if (!properties[static_cast<int>(meta_function::pairs)]) {
const char* name = to_string(meta_function::pairs).c_str();
opregs[opregsindex] = { name, container_usertype_metatable<as_container_t<T>>::pairs_call };
++opregsindex;
}
if (!properties[static_cast<int>(meta_function::length)]) {
usertype_detail::make_length_op<T>(opregs, opregsindex);
}
if (!properties[static_cast<int>(meta_function::to_string)]) {
usertype_detail::make_to_string_op<T, meta::supports_ostream_op<T>>(opregs, opregsindex);
}
if (!properties[static_cast<int>(meta_function::call)]) {
usertype_detail::make_call_op<T>(opregs, opregsindex);
}
auto prop_fx = [&](meta_function mf) { return !properties[static_cast<int>(mf)]; };
usertype_detail::insert_default_registrations<T>(opregs, opregsindex, prop_fx);
t.push();
luaL_setfuncs(L, opregs, 0);
t.pop();

View File

@ -159,34 +159,41 @@ namespace sol {
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
typedef meta::count_for_pack<lua_size, Args...> expected_count;
return call<check_args>(tr, ta, L, (std::max)(static_cast<int>(lua_gettop(L) - expected_count::value), static_cast<int>(0)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
typedef meta::count_for_pack<lua_size, Args...> expected_count;
call<check_args>(tr, ta, L, (std::max)(static_cast<int>(lua_gettop(L) - expected_count::value), static_cast<int>(0)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template<bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename... Args, typename Fx, typename... FxArgs>
inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
lua_settop(L, 0);
if (clean_stack) {
lua_settop(L, 0);
}
return 0;
}
template<bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
lua_settop(L, 0);
typedef is_stack_based<meta::unqualified_t<decltype(r)>> is_stack;
if (clean_stack && !is_stack::value) {
lua_settop(L, 0);
}
return push_reference(L, std::forward<decltype(r)>(r));
}
template<bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs>
template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::returns_list returns_list;
return call_into_lua<check_args>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
}
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) {

View File

@ -87,18 +87,45 @@ namespace sol {
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#if SOL_LUA_VERSION >= 503
if (lua_isinteger(L, index) != 0) {
#ifdef SOL_STRINGS_ARE_NUMBERS
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
#else
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
#endif
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0 && static_cast<lua_Number>(std::llround(v)) == v;
const bool success = false;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index));
}
return success;
#else
#ifndef SOL_STRINGS_ARE_NUMBERS
// must pre-check, because it will convert
type t = type_of(L, index);
if (t != type::number) {
// expected type, actual type
handler(L, index, type::number, t);
return false;
}
#endif // Do not allow strings to be numbers
int isnum = 0;
const lua_Number v = lua_tonumberx(L, index, &isnum);
const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;
if (!success) {
// expected type, actual type
#ifndef SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, t);
#else
handler(L, index, type::number, type_of(L, index));
#endif
}
return success;
#endif
}
};
@ -107,12 +134,22 @@ namespace sol {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
#ifdef SOL_STRINGS_ARE_NUMBERS
type t = type_of(L, index);
bool success = t == type::number;
if (!success) {
// expected type, actual type
handler(L, index, type::number, t);
}
return success;
#else
bool success = lua_isnumber(L, index) == 1;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index));
}
return success;
#endif
}
};

View File

@ -67,7 +67,7 @@ namespace sol {
const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) {
#if 1 // defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = std::llround(value);
const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1);
return static_cast<T>(integer_value);

View File

@ -29,9 +29,13 @@
#include "traits.hpp"
#include "tie.hpp"
#include "stack_guard.hpp"
#include "demangle.hpp"
#include "forward_detail.hpp"
#include <vector>
#include <forward_list>
#include <string>
#include <algorithm>
namespace sol {
namespace detail {
@ -52,17 +56,8 @@ namespace sol {
return 0;
}
template <typename T, typename Real>
inline void usertype_unique_alloc_destroy(void* memory) {
T** pointerpointer = static_cast<T**>(memory);
unique_destructor* dx = static_cast<unique_destructor*>(static_cast<void*>(pointerpointer + 1));
Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
std::allocator<Real> alloc;
alloc.destroy(target);
}
template <typename T>
inline int user_alloc_destroy(lua_State* L) {
inline int user_alloc_destruct(lua_State* L) {
void* rawdata = lua_touserdata(L, 1);
T* data = static_cast<T*>(rawdata);
std::allocator<T> alloc;
@ -71,7 +66,7 @@ namespace sol {
}
template <typename T>
inline int usertype_alloc_destroy(lua_State* L) {
inline int usertype_alloc_destruct(lua_State* L) {
void* rawdata = lua_touserdata(L, 1);
T** pdata = static_cast<T**>(rawdata);
T* data = *pdata;
@ -80,6 +75,20 @@ namespace sol {
return 0;
}
template <typename T>
inline int cannot_destruct(lua_State* L) {
return luaL_error(L, "cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= delete' and thusly this type is being destroyed without properly destructing, invoking undefined behavior", detail::demangle<T>().data());
}
template <typename T, typename Real>
inline void usertype_unique_alloc_destroy(void* memory) {
T** pointerpointer = static_cast<T**>(memory);
unique_destructor* dx = static_cast<unique_destructor*>(static_cast<void*>(pointerpointer + 1));
Real* target = static_cast<Real*>(static_cast<void*>(dx + 1));
std::allocator<Real> alloc;
alloc.destroy(target);
}
template <typename T>
void reserve(T&, std::size_t) {}

View File

@ -68,7 +68,7 @@ namespace sol {
return static_cast<T>(lua_tointeger(L, index));
}
#endif
return static_cast<T>(std::llround(lua_tonumber(L, index)));
return static_cast<T>(llround(lua_tonumber(L, index)));
}
};

View File

@ -26,6 +26,8 @@
#include "raii.hpp"
#include "optional.hpp"
#include "usertype_traits.hpp"
#include "filters.hpp"
#include <memory>
#include <type_traits>
#include <cassert>
@ -83,10 +85,8 @@ namespace sol {
template <typename K, typename... Args>
static int push_keyed(lua_State* L, K&& k, Args&&... args) {
return push_fx(L, [&L, &k]() {
luaL_newmetatable(L, &k[0]);
lua_setmetatable(L, -2);
}, std::forward<Args>(args)...);
stack_detail::undefined_metatable<T> fx(L, &k[0]);
return push_fx(L, fx, std::forward<Args>(args)...);
}
template <typename... Args>
@ -97,6 +97,8 @@ namespace sol {
template <typename T>
struct pusher<detail::as_pointer_tag<T>> {
typedef meta::unqualified_t<T> U;
template <typename F>
static int push_fx(lua_State* L, F&& f, T* obj) {
if (obj == nullptr)
@ -109,14 +111,12 @@ namespace sol {
template <typename K>
static int push_keyed(lua_State* L, K&& k, T* obj) {
return push_fx(L, [&L, &k]() {
luaL_newmetatable(L, &k[0]);
lua_setmetatable(L, -2);
}, obj);
stack_detail::undefined_metatable<U*> fx(L, &k[0]);
return push_fx(L, fx, obj);
}
static int push(lua_State* L, T* obj) {
return push_keyed(L, usertype_traits<meta::unqualified_t<T>*>::metatable(), obj);
return push_keyed(L, usertype_traits<U*>::metatable(), obj);
}
};
@ -171,7 +171,12 @@ namespace sol {
detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<P>>::metatable()[0]) == 1) {
set_field(L, "__gc", detail::unique_destruct<P>);
luaL_Reg l[32]{};
int index = 0;
auto prop_fx = [](meta_function) { return true; };
usertype_detail::insert_default_registrations<P>(l, index, prop_fx);
usertype_detail::make_destructor<T>(l, index);
luaL_setfuncs(L, l, 0);
}
lua_setmetatable(L, -2);
return 1;
@ -213,7 +218,7 @@ namespace sol {
}
#endif
#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
if (static_cast<T>(std::llround(static_cast<lua_Number>(value))) != value) {
if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {
#ifndef SOL_NO_EXCEPTIONS
throw sol::error("The integer will be misrepresented in lua.");
#else
@ -437,7 +442,7 @@ namespace sol {
std::allocator<T> alloc;
alloc.construct(data, std::forward<Args>(args)...);
if (with_meta) {
lua_CFunction cdel = detail::user_alloc_destroy<T>;
lua_CFunction cdel = detail::user_alloc_destruct<T>;
// Make sure we have a plain GC set for this data
if (luaL_newmetatable(L, name) != 0) {
lua_pushcclosure(L, cdel, 0);
@ -561,6 +566,30 @@ namespace sol {
}
};
template <>
struct pusher<absolute_index> {
static int push(lua_State* L, absolute_index ai) {
lua_pushvalue(L, ai);
return 1;
}
};
template <>
struct pusher<raw_index> {
static int push(lua_State* L, raw_index ri) {
lua_pushvalue(L, ri);
return 1;
}
};
template <>
struct pusher<ref_index> {
static int push(lua_State* L, ref_index ri) {
lua_rawgeti(L, LUA_REGISTRYINDEX, ri);
return 1;
}
};
#ifdef SOL_CODECVT_SUPPORT
template<>
struct pusher<const wchar_t*> {

View File

@ -32,9 +32,10 @@ namespace sol {
(void)L;
return -1;
#else
const char* message = lua_tostring(L, -1);
size_t messagesize;
const char* message = lua_tolstring(L, -1, &messagesize);
if (message) {
std::string err = message;
std::string err(message, messagesize);
lua_settop(L, 0);
throw error(err);
}

View File

@ -450,6 +450,10 @@ namespace sol {
return load_result(L, absolute_index(L, -1), 1, 1, x);
}
load_result load_buffer(const char* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return load(string_view(buff, size), chunkname, mode);
}
load_result load_file(const std::string& filename, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
return load_result(L, absolute_index(L, -1), 1, 1, x);
@ -457,7 +461,7 @@ namespace sol {
load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
char basechunkname[17] = {};
const char* chunknametarget = detail::make_chunk_name("lua_reader", chunkname, basechunkname);
const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname);
#if SOL_LUA_VERSION > 501
load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str()));
#else

View File

@ -176,7 +176,7 @@ namespace sol {
basic_table_core& operator=(basic_table_core&&) = default;
basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler>
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {}
basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) {
if (!std::is_base_of<stack_reference, base_type>::value) {

View File

@ -261,7 +261,7 @@ namespace sol {
using no = struct { char s[2]; };
struct F { void operator()(); };
struct Derived : T, F {};
struct Derived : T, F { ~Derived() = delete; };
template<typename U, U> struct Check;
template<typename V>
@ -382,6 +382,35 @@ namespace sol {
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
struct has_to_string_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().to_string())*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
#if defined(_MSC_VER) && _MSC_VER <= 1910
template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())>
std::true_type supports_op_less_test(std::reference_wrapper<T>, std::reference_wrapper<U>);
std::false_type supports_op_less_test(...);
template <typename T, typename U, typename = decltype(std::declval<T&>() == std::declval<U&>())>
std::true_type supports_op_equal_test(std::reference_wrapper<T>, std::reference_wrapper<U>);
std::false_type supports_op_equal_test(...);
template <typename T, typename U, typename = decltype(std::declval<T&>() <= std::declval<U&>())>
std::true_type supports_op_less_equal_test(std::reference_wrapper<T>, std::reference_wrapper<U>);
std::false_type supports_op_less_equal_test(...);
template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())>
std::true_type supports_ostream_op(std::reference_wrapper<T>, std::reference_wrapper<OS>);
std::false_type supports_ostream_op(...);
template <typename T, typename = decltype(to_string(std::declval<T&>()))>
std::true_type supports_adl_to_string(std::reference_wrapper<T>);
std::false_type supports_adl_to_string(...);
#else
template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())>
std::true_type supports_op_less_test(const T&, const U&);
std::false_type supports_op_less_test(...);
@ -394,9 +423,24 @@ namespace sol {
template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())>
std::true_type supports_ostream_op(const T&, const OS&);
std::false_type supports_ostream_op(...);
template <typename T, typename = decltype(to_string(std::declval<T&>()))>
std::true_type supports_adl_to_string(const T&);
std::false_type supports_adl_to_string(...);
#endif
} // meta_detail
#if defined(_MSC_VER) && _MSC_VER <= 1910
template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = T>
using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = T>
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = std::ostream>
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T>
using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval<T&>())));
#else
template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = T>
@ -405,6 +449,11 @@ namespace sol {
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = std::ostream>
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>()));
template <typename T>
using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval<T&>()));
#endif
template <typename T>
using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>;
template<typename T>
struct is_callable : boolean<meta_detail::is_callable<T>::value> {};

View File

@ -26,8 +26,12 @@
#include "optional.hpp"
#include "compatibility.hpp"
#include "forward.hpp"
#include "forward_detail.hpp"
#include "traits.hpp"
#include "string_shim.hpp"
#include "raii.hpp"
#include "filters.hpp"
#include <array>
#include <string>
#ifdef SOL_CXX17_FEATURES
@ -1042,6 +1046,13 @@ namespace sol {
template <>
struct is_lua_index<upvalue_index> : std::true_type {};
template <typename T>
struct is_stack_based : std::is_base_of<stack_reference, T> {};
template <>
struct is_stack_based<raw_index> : std::true_type {};
template <>
struct is_stack_based<absolute_index> : std::true_type {};
template <typename Signature>
struct lua_bind_traits : meta::bind_traits<Signature> {
private:
@ -1083,6 +1094,48 @@ namespace sol {
inline type type_of() {
return lua_type_of<meta::unqualified_t<T>>::value;
}
namespace detail {
template <typename T>
struct is_non_factory_constructor : std::false_type {};
template <typename... Args>
struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
template <typename... Args>
struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
template <>
struct is_non_factory_constructor<no_construction> : std::true_type {};
template <typename T>
struct is_constructor : is_non_factory_constructor<T> {};
template <typename... Args>
struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
template <typename T>
struct is_constructor<protect_t<T>> : is_constructor<meta::unqualified_t<T>> {};
template <typename F, typename... Filters>
struct is_constructor<filter_wrapper<F, Filters...>> : is_constructor<meta::unqualified_t<F>> {};
template <typename... Args>
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
template <typename T>
struct is_destructor : std::false_type {};
template <typename Fx>
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
template <typename... Args>
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
struct add_destructor_tag {};
struct check_destructor_tag {};
struct verified_tag {} const verified{};
} // detail
} // sol
#endif // SOL_TYPES_HPP

View File

@ -81,7 +81,7 @@ namespace sol {
basic_function& operator=(basic_function&&) = default;
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS

View File

@ -48,7 +48,7 @@ namespace sol {
basic_userdata& operator=(basic_userdata&&) = default;
basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler>
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
@ -85,7 +85,7 @@ namespace sol {
basic_lightuserdata& operator=(basic_lightuserdata&&) = default;
basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler>
template <typename T, meta::enable<meta::neg<is_lua_index<T>>> = meta::enabler>
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS

View File

@ -36,24 +36,26 @@ namespace sol {
std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister;
template<typename... Args>
usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) {}
usertype(detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) {
static_assert(detail::has_destructor<Args...>::value, "this type does not have an explicit destructor declared; please pass a custom destructor function wrapped in sol::destruct, especially if the type does not have an accessible (private) destructor");
}
template<typename... Args>
usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
usertype(detail::add_destructor_tag, Args&&... args) : usertype(detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
template<typename... Args>
usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward<Args>(args)...) {}
usertype(detail::check_destructor_tag, Args&&... args) : usertype(meta::condition<meta::all<std::is_destructible<T>, meta::neg<detail::has_destructor<Args...>>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward<Args>(args)...) {}
public:
template<typename... Args>
usertype(Args&&... args) : usertype(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward<Args>(args)...) {}
usertype(Args&&... args) : usertype(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<detail::has_constructor<Args...>>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward<Args>(args)...) {}
template<typename... Args, typename... CArgs>
usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args, typename... Fxs>
usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) : usertype(detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args>
usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter<simple_usertype_metatable<T>, detail::deleter>(L, std::forward<Args>(args)...)) {}

235
sol/usertype_core.hpp Normal file
View File

@ -0,0 +1,235 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_USERTYPE_CORE_HPP
#define SOL_USERTYPE_CORE_HPP
#include "wrapper.hpp"
#include "call.hpp"
#include "stack.hpp"
#include "types.hpp"
#include "stack_reference.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "raii.hpp"
#include "deprecate.hpp"
#include "object.hpp"
#include <sstream>
namespace sol {
namespace usertype_detail {
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
template <typename T>
inline int member_default_to_string(std::true_type, lua_State* L) {
std::string ts = stack::get<T>(L, 1).to_string();
return stack::push(L, std::move(ts));
}
template <typename T>
inline int member_default_to_string(std::false_type, lua_State* L) {
return luaL_error(L, "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member function, or operator<<(ostream&, ...) present", detail::demangle<T>().data());
}
template <typename T>
inline int adl_default_to_string(std::true_type, lua_State* L) {
using std::to_string;
std::string ts = to_string(stack::get<T>(L, 1));
return stack::push(L, std::move(ts));
}
template <typename T>
inline int adl_default_to_string(std::false_type, lua_State* L) {
return member_default_to_string<T>(meta::supports_to_string_member<T>(), L);
}
template <typename T>
inline int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::get<T>(L, 1);
return stack::push(L, oss.str());
}
template <typename T>
inline int oss_default_to_string(std::false_type, lua_State* L) {
return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);
}
template <typename T>
inline int default_to_string(lua_State* L) {
return oss_default_to_string<T>(meta::supports_ostream_op<T>(), L);
}
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
auto maybel = stack::check_get<T>(L, 1);
if (maybel) {
auto mayber = stack::check_get<T>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (std::is_same<no_comp, Op>::value) {
return stack::push(L, detail::ptr(l) == detail::ptr(r));
}
else {
Op op;
return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
}
}
}
return stack::push(L, false);
}
template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_reg_op(Regs& l, int& index, const char* name) {
lua_CFunction f = &comparsion_operator_wrap<T, Op>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Op, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_reg_op(Regs&, int&, const char*) {
// Do nothing if there's no support
}
template <typename T, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_to_string_op(Regs& l, int& index) {
const char* name = to_string(meta_function::to_string).c_str();
lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_to_string_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs& l, int& index) {
const char* name = to_string(meta_function::call).c_str();
lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs& l, int& index) {
const char* name = to_string(meta_function::length).c_str();
l[index] = luaL_Reg{ name, &c_call<decltype(&T::size), &T::size> };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>>>
void make_destructor(Regs& l, int& index) {
const char* name = to_string(meta_function::garbage_collect).c_str();
l[index] = luaL_Reg{ name, is_unique_usertype<T>::value ? &detail::unique_destruct<T> : &detail::usertype_alloc_destruct<T> };
++index;
}
template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>>>
void make_destructor(Regs& l, int& index) {
if (!std::is_destructible<T>::value) {
// if the value is not destructible, plant an erroring __gc method
// to warn the user of a problem when it comes around
// this won't trigger if the user performs `new_usertype` / `new_simple_usertype` and
// rigs the class up properly
const char* name = to_string(meta_function::garbage_collect).c_str();
l[index] = luaL_Reg{ name, &detail::cannot_destruct<T> };
++index;
}
}
template <typename T, typename Regs, typename Fx>
void insert_default_registrations(Regs& l, int& index, Fx&& fx) {
if (fx(meta_function::less_than)) {
const char* name = to_string(meta_function::less_than).c_str();
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name);
}
if (fx(meta_function::less_than_or_equal_to)) {
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name);
}
if (fx(meta_function::equal_to)) {
const char* name = to_string(meta_function::equal_to).c_str();
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name);
}
if (fx(meta_function::pairs)) {
const char* name = to_string(meta_function::pairs).c_str();
l[index] = luaL_Reg{ name, container_usertype_metatable<as_container_t<T>>::pairs_call };
++index;
}
if (fx(meta_function::length)) {
usertype_detail::make_length_op<T>(l, index);
}
if (fx(meta_function::to_string)) {
usertype_detail::make_to_string_op<T, meta::any<meta::supports_to_string_member<T>, meta::supports_adl_to_string<T>, meta::supports_ostream_op<T>>>(l, index);
}
if (fx(meta_function::call_function)) {
usertype_detail::make_call_op<T>(l, index);
}
}
} // usertype_detail
namespace stack {
namespace stack_detail {
template <typename T>
struct undefined_metatable {
typedef meta::all<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> is_destructible;
typedef std::remove_pointer_t<T> P;
lua_State* L;
const char* key;
undefined_metatable(lua_State* l, const char* k) : L(l), key(k) {}
void operator () () const {
if (luaL_newmetatable(L, key) == 1) {
luaL_Reg l[32]{};
int index = 0;
auto fx = [](meta_function) { return true; };
usertype_detail::insert_default_registrations<P>(l, index, fx);
usertype_detail::make_destructor<T>(l, index);
luaL_setfuncs(L, l, 0);
}
lua_setmetatable(L, -2);
}
};
} // stack_detail
} // stack
} // sol
#endif // SOL_USERTYPE_CORE_HPP

View File

@ -33,6 +33,7 @@
#include "deprecate.hpp"
#include "object.hpp"
#include "container_usertype_metatable.hpp"
#include "usertype_core.hpp"
#include <unordered_map>
#include <cstdio>
#include <sstream>
@ -102,13 +103,6 @@ namespace sol {
index(std::move(i)), newindex(std::move(ni)),
indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
};
template <typename T>
inline int default_to_string(lua_State* L) {
std::ostringstream oss;
oss << stack::get<T>(L, 1);
return stack::push(L, oss.str());
}
} // usertype_detail
struct usertype_metatable_core {
@ -134,47 +128,6 @@ namespace sol {
namespace usertype_detail {
const lua_Integer toplevel_magic = static_cast<lua_Integer>(0xCCC2CCC1);
struct add_destructor_tag {};
struct check_destructor_tag {};
struct verified_tag {} const verified{};
template <typename T>
struct is_non_factory_constructor : std::false_type {};
template <typename... Args>
struct is_non_factory_constructor<constructors<Args...>> : std::true_type {};
template <typename... Args>
struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {};
template <>
struct is_non_factory_constructor<no_construction> : std::true_type {};
template <typename T>
struct is_constructor : is_non_factory_constructor<T> {};
template <typename... Args>
struct is_constructor<factory_wrapper<Args...>> : std::true_type {};
template <typename... Args>
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
template <typename T>
struct is_destructor : std::false_type {};
template <typename Fx>
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
template <typename... Args>
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
inline int is_indexer(string_detail::string_shim s) {
if (s == to_string(meta_function::index)) {
return 1;
@ -409,76 +362,6 @@ namespace sol {
(void)accessor;
(void)detail::swallow{ 0, (walk_single_base<is_index, Bases>(L, found, ret, accessor), 0)... };
}
template <typename T, typename Op>
int operator_wrap(lua_State* L) {
auto maybel = stack::check_get<T>(L, 1);
if (maybel) {
auto mayber = stack::check_get<T>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (std::is_same<no_comp, Op>::value) {
return stack::push(L, detail::ptr(l) == detail::ptr(r));
}
else {
Op op;
return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r)));
}
}
}
return stack::push(L, false);
}
template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_reg_op(Regs& l, int& index, const char* name) {
lua_CFunction f = &operator_wrap<T, Op>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Op, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_reg_op(Regs&, int&, const char*) {
// Do nothing if there's no support
}
template <typename T, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
inline void make_to_string_op(Regs& l, int& index) {
const char* name = to_string(meta_function::to_string).c_str();
lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
inline void make_to_string_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs& l, int& index) {
const char* name = to_string(meta_function::call).c_str();
lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>;
l[index] = luaL_Reg{ name, f };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_deducible_signature<T>> = meta::enabler>
inline void make_call_op(Regs&, int&) {
// Do nothing if there's no support
}
template <typename T, typename Regs, meta::enable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs& l, int& index) {
const char* name = to_string(meta_function::length).c_str();
l[index] = luaL_Reg{ name, &c_call<decltype(&T::size), &T::size> };
++index;
}
template <typename T, typename Regs, meta::disable<meta::has_size<T>> = meta::enabler>
inline void make_length_op(Regs&, int&) {
// Do nothing if there's no support
}
} // usertype_detail
template <typename T>
@ -536,32 +419,8 @@ namespace sol {
}
int finish_regs(regs_t& l, int& index) {
if (!properties[static_cast<int>(meta_function::less_than)]) {
const char* name = to_string(meta_function::less_than).c_str();
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name);
}
if (!properties[static_cast<int>(meta_function::less_than_or_equal_to)]) {
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name);
}
if (!properties[static_cast<int>(meta_function::equal_to)]) {
const char* name = to_string(meta_function::equal_to).c_str();
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name);
}
if (!properties[static_cast<int>(meta_function::pairs)]) {
const char* name = to_string(meta_function::pairs).c_str();
l[index] = luaL_Reg{ name, container_usertype_metatable<as_container_t<T>>::pairs_call };
++index;
}
if (!properties[static_cast<int>(meta_function::length)]) {
usertype_detail::make_length_op<T>(l, index);
}
if (!properties[static_cast<int>(meta_function::to_string)]) {
usertype_detail::make_to_string_op<T, meta::supports_ostream_op<T>>(l, index);
}
if (!properties[static_cast<int>(meta_function::call)]) {
usertype_detail::make_call_op<T>(l, index);
}
auto prop_fx = [&](meta_function mf) { return !properties[static_cast<int>(mf)]; };
usertype_detail::insert_default_registrations<T>(l, index, prop_fx);
if (destructfunc != nullptr) {
l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), destructfunc };
++index;
@ -732,7 +591,7 @@ namespace sol {
typedef meta::unqualified_tuple_element_t<Idx - 1, Tuple> K;
typedef meta::unqualified_tuple_element_t<Idx, Tuple> F;
static const int boost =
!usertype_detail::is_non_factory_constructor<F>::value
!detail::is_non_factory_constructor<F>::value
&& std::is_same<K, call_construction>::value ?
1 : 0;
auto& f = std::get<Idx>(um.functions);

View File

@ -1,4 +1,4 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
@ -94,7 +94,7 @@ namespace sol {
template <typename T>
void sequence_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
auto r1 = lua.safe_script(R"(
for i=1,#c do
v = c[i]
assert(v == (i + 10))
@ -104,45 +104,45 @@ end
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(1)", sol::script_pass_on_error);
auto r1 = lua.safe_script("v1 = c:get(1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(3)", sol::script_pass_on_error);
auto r2 = lua.safe_script("v2 = c:get(3)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(2, 20)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(6, 16)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[#c + 1] = 18", sol::script_pass_on_error);
auto r = lua.safe_script("c[#c + 1] = 18", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[#c]", sol::script_pass_on_error);
auto r = lua.safe_script("v3 = c[#c]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
@ -203,7 +203,7 @@ end
template <typename T>
void ordered_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
auto r1 = lua.safe_script(R"(
for i=1,#c do
v = c[(i + 10)]
assert(v == (i + 10))
@ -213,45 +213,45 @@ end
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = true", sol::script_pass_on_error);
auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
@ -313,45 +313,45 @@ template <typename T>
void unordered_container_check(sol::state& lua, T& items) {
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:set(20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:set(16)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = true", sol::script_pass_on_error);
auto r = lua.safe_script("c[18] = true", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
@ -398,7 +398,7 @@ void unordered_container_check(sol::state& lua, T& items) {
template <typename T>
void associative_ordered_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
auto r1 = lua.safe_script(R"(
for i=1,#c do
v = c[(i + 10)]
assert(v == (i + 20))
@ -408,47 +408,47 @@ end
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20, 30)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16, 26)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r3 = lua.script("c:set(12, 31)", sol::script_pass_on_error);
auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error);
REQUIRE(r3.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17, 27)", sol::script_pass_on_error);
auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = 28", sol::script_pass_on_error);
auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
@ -518,47 +518,47 @@ template <typename T>
void associative_unordered_container_check(sol::state& lua, T& items) {
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
auto r2 = lua.safe_script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20, 30)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:set(20, 30)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16, 26)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:set(16, 26)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r3 = lua.script("c:set(12, 31)", sol::script_pass_on_error);
auto r3 = lua.safe_script("c:set(12, 31)", sol::script_pass_on_error);
REQUIRE(r3.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:erase(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:erase(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17, 27)", sol::script_pass_on_error);
auto r = lua.safe_script("c:add(17, 27)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = 28", sol::script_pass_on_error);
auto r = lua.safe_script("c[18] = 28", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
auto r = lua.safe_script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
@ -612,7 +612,7 @@ void associative_unordered_container_check(sol::state& lua, T& items) {
template <typename T>
void fixed_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
auto r1 = lua.safe_script(R"(
for i=1,#c do
v = c[i]
assert(v == (i + 10))
@ -622,45 +622,45 @@ end
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
auto r1 = lua.safe_script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(2)", sol::script_pass_on_error);
auto r1 = lua.safe_script("v1 = c:get(2)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(5)", sol::script_pass_on_error);
auto r2 = lua.safe_script("v2 = c:get(5)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(2, 20)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:set(2, 20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(6, 16)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:set(6, 16)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
auto r5 = lua.safe_script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
auto r1 = lua.safe_script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE_FALSE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
auto r3 = lua.safe_script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
auto r2 = lua.safe_script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
auto r4 = lua.safe_script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
auto r = lua.safe_script("c:add(17)", sol::script_pass_on_error);
REQUIRE_FALSE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[5] = 18", sol::script_pass_on_error);
auto r = lua.safe_script("c[5] = 18", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[4]", sol::script_pass_on_error);
auto r = lua.safe_script("v3 = c[4]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
@ -892,7 +892,7 @@ TEST_CASE("containers/auxiliary functions test", "make sure the manipulation fun
sol::state lua;
lua.open_libraries();
lua.script(R"(
lua.safe_script(R"(
function g (x)
x:add(20)
end
@ -962,7 +962,7 @@ end
REQUIRE(set.empty());
REQUIRE_NOTHROW([&]() {
lua.script(R"(
lua.safe_script(R"(
c_arr[1] = 7
c_arr[2] = 7
c_arr[3] = 7

View File

@ -36,7 +36,7 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b
lua.set_function("f", [&]() -> std::vector<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::object x = lua["x"];
sol::type xt = x.get_type();
REQUIRE(xt == sol::type::userdata);
@ -62,8 +62,8 @@ TEST_CASE("containers/table conversion", "test table conversions with as_table a
return sol::as_nested(std::vector<std::string>{"bark", "woof"});
});
lua.script("v1 = bark()");
lua.script("v2 = woof()");
lua.safe_script("v1 = bark()");
lua.safe_script("v2 = woof()");
sol::as_table_t<std::vector<std::string>> as_table_strings = lua["v1"];
sol::nested<std::vector<std::string>> nested_strings = lua["v2"];
@ -79,7 +79,7 @@ TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped
lua.set_function("f", [&]() -> std::vector<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::vector<int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -91,7 +91,7 @@ TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped")
lua.set_function("f", [&]() -> std::deque<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::deque<int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -103,7 +103,7 @@ TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped")
lua.set_function("f", [&]() -> std::array<int, 3>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::array<int, 3> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -115,7 +115,7 @@ TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") {
lua.set_function("f", [&]() -> std::list<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::list <int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -127,7 +127,7 @@ TEST_CASE("containers/forward_list roundtrip", "make sure forward_lists can be r
lua.set_function("f", [&]() -> std::forward_list<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::forward_list <int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -139,7 +139,7 @@ TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") {
lua.set_function("f", [&]() -> std::map<std::string, int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::map<std::string, int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -151,7 +151,7 @@ TEST_CASE("containers/unordered_map roundtrip", "make sure unordered_maps can be
lua.set_function("f", [&]() -> std::unordered_map<std::string, int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::unordered_map<std::string, int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -163,7 +163,7 @@ TEST_CASE("containers/unordered_set roundtrip", "make sure unordered_sets can be
lua.set_function("f", [&]() -> std::unordered_set<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::unordered_set<int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -175,7 +175,7 @@ TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") {
lua.set_function("f", [&]() -> std::set<int>& {
return v;
});
lua.script("x = f()");
lua.safe_script("x = f()");
std::set<int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
@ -187,7 +187,7 @@ TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-t
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::vector<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -199,7 +199,7 @@ TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tri
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::deque<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -211,7 +211,7 @@ TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tri
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::array<int, 3>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -223,7 +223,7 @@ TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripp
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::list <int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -235,7 +235,7 @@ TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists ca
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::forward_list<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -247,7 +247,7 @@ TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::map<std::string, int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -259,7 +259,7 @@ TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -271,7 +271,7 @@ TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::unordered_set<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -283,7 +283,7 @@ TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
lua.safe_script("x = f()");
sol::as_table_t<std::set<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
@ -304,11 +304,11 @@ TEST_CASE("containers/custom usertype", "make sure container usertype metatables
);
bark obj{ { 24, 50 } };
lua.set("a", &obj);
REQUIRE_NOTHROW(lua.script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.script("a:something()"));
REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.safe_script("a:something()"));
lua.set("a", obj);
REQUIRE_NOTHROW(lua.script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.script("a:something()"));
REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.safe_script("a:something()"));
}
TEST_CASE("containers/const serialization kvp", "make sure const keys / values are respected") {
@ -318,10 +318,10 @@ TEST_CASE("containers/const serialization kvp", "make sure const keys / values a
lua.open_libraries();
bark obj{ { 24, 50 } };
lua.set("a", &obj);
REQUIRE_NOTHROW(lua.script("assert(a[24] == 50)"));
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.script("assert(a[24] == 50)"));
REQUIRE_NOTHROW(lua.safe_script("assert(a[24] == 50)"));
}
TEST_CASE("containers/basic serialization", "make sure containers are turned into proper userdata and have basic hooks established") {
@ -330,20 +330,20 @@ TEST_CASE("containers/basic serialization", "make sure containers are turned int
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.script("for k = 1, #b do assert(k == b[k]) end")
lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
);
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.script("for k = 1, #b do assert(k == b[k]) end")
lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
);
lua.set("b", &w);
REQUIRE_NOTHROW(
lua.script("for k = 1, #b do assert(k == b[k]) end")
lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
);
lua.set("b", std::ref(w));
REQUIRE_NOTHROW(
lua.script("for k = 1, #b do assert(k == b[k]) end")
lua.safe_script("for k = 1, #b do assert(k == b[k]) end")
);
}
@ -354,7 +354,7 @@ TEST_CASE("containers/const serialization", "make sure containers are turned int
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.script("for k, v in pairs(b) do assert(k == v) end");
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());
@ -367,20 +367,20 @@ TEST_CASE("containers/table serialization", "ensure types can be serialized as t
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.script("for k, v in ipairs(b) do assert(k == v) end")
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
);
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.script("for k, v in ipairs(b) do assert(k == v) end")
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
);
lua.set("b", sol::as_table(&w));
REQUIRE_NOTHROW(
lua.script("for k, v in ipairs(b) do assert(k == v) end")
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
);
lua.set("b", sol::as_table(std::ref(w)));
REQUIRE_NOTHROW(
lua.script("for k, v in ipairs(b) do assert(k == v) end")
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end")
);
}
@ -404,7 +404,7 @@ TEST_CASE("containers/const correctness", "usertype metatable names should reaso
std::vector<Vec const *> bar;
bar.push_back(&vec);
lua.script(R"(
lua.safe_script(R"(
func = function(vecs)
for i = 1, #vecs do
vec = vecs[i]
@ -427,20 +427,20 @@ 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.script("a = test_one()"));
REQUIRE_NOTHROW(lua.script("b = test_two()"));
REQUIRE_NOTHROW(lua.script("c = test_three()"));
REQUIRE_NOTHROW(lua.script("d = test_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()"));
REQUIRE_NOTHROW(lua.script("assert(#a == 10, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(a[3] == 3, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(b.one == 1, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(b.three == 3, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(c.name == 'Rapptz', 'error')"));
REQUIRE_NOTHROW(lua.script("assert(c.project == 'sol', 'error')"));
REQUIRE_NOTHROW(lua.script("assert(d.one == 1, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(d.three == 3, 'error')"));
REQUIRE_NOTHROW(lua.script("assert(d.four == 4, 'error')"));
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')"));
sol::table a = lua.get<sol::table>("a");
sol::table b = lua.get<sol::table>("b");
@ -483,7 +483,7 @@ TEST_CASE("containers/usertype transparency", "Make sure containers pass their a
"a_list", &B::a_list
);
lua.script(R"(
lua.safe_script(R"(
b = B.new()
a_ref = b.a_list[2]
)");
@ -548,7 +548,7 @@ TEST_CASE("containers/is container", "make sure the is_container trait behaves p
machine m;
lua["machine"] = &m;
lua.script(R"(
lua.safe_script(R"(
machine:opt():output_help()
)");
@ -577,7 +577,7 @@ TEST_CASE("containers/readonly", "make sure readonly members are stored appropri
);
lua["value"] = std::list<bar>{ {},{},{} };
lua.script(R"(
lua.safe_script(R"(
a = foo.new()
x = a.seq
a.seq = value
@ -597,7 +597,7 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") {
sol::state lua;
lua.open_libraries();
lua.script("function f (a, b, c, d) print(a, b, c, d) return a, b, c, d end");
lua.safe_script("function f (a, b, c, d) print(a, b, c, d) return a, b, c, d end");
sol::function f = lua["f"];
int a, b, c, d;
@ -637,11 +637,11 @@ TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly
return std::vector<thing*>(5, &t);
});
lua.script(R"(
lua.safe_script(R"(
c = f()
)");
lua.script(R"(
lua.safe_script(R"(
check = {}
local i = 1
while c[i] do
@ -660,7 +660,7 @@ end
TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script(
lua.safe_script(
R"(
function f_fill(vec)
print("#vec in lua: " .. #vec)
@ -817,13 +817,13 @@ TEST_CASE("containers/input iterators", "test shitty input iterators that are al
not_really_a_container c;
lua["c"] = &c;
#if SOL_LUA_VERSION > 502
lua.script(R"lua(
lua.safe_script(R"lua(
for k, v in pairs(c) do
assert((k - 1) == v:val())
end
)lua");
#endif
lua.script(R"lua(
lua.safe_script(R"lua(
for k=1,#c do
v = c[k]
assert((k - 1) == v:val())
@ -849,10 +849,10 @@ TEST_CASE("containers/pairs", "test how well pairs work with the underlying syst
lua["c"] = std::ref(c);
lua["d"] = &d;
lua.script("av1, av2 = a:get(1)");
lua.script("bv1, bv2 = b:get(1)");
lua.script("cv1, cv2 = c:get(1)");
lua.script("dv1, dv2 = d:get(1)");
lua.safe_script("av1, av2 = a:get(1)");
lua.safe_script("bv1, bv2 = b:get(1)");
lua.safe_script("cv1, cv2 = c:get(1)");
lua.safe_script("dv1, dv2 = d:get(1)");
std::vector<std::pair<std::string, int>>& la = lua["a"];
std::array<std::pair<std::string, int>, 5>& lb = lua["b"];

View File

@ -18,7 +18,7 @@ end
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script);
lua.safe_script(script);
sol::coroutine cr = lua["loop"];
int counter;
@ -47,7 +47,7 @@ end
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script);
lua.safe_script(script);
sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state();
sol::coroutine cr = runnerstate["loop"];

View File

@ -68,7 +68,7 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio
sol::state lua;
// Create a pass-through style of function
lua.script("function f ( a, b, c ) return a + c, b end");
lua.safe_script("function f ( a, b, c ) return a + c, b end");
lua.set_function("g", [](int a, bool b, int c, double d) {
return std::make_tuple(a + c, b, d + 2.5);
});

View File

@ -1,7 +1,8 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <iostream>
#include "test_stack_guard.hpp"
@ -11,7 +12,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base);
lua.script("f = function() return test end");
lua.safe_script("f = function() return test end");
sol::function f = lua["f"];
sol::environment env_f(lua, sol::create);
@ -21,7 +22,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
int result = f();
REQUIRE(result == 31);
lua.script("g = function() test = 5 end");
lua.safe_script("g = function() test = 5 end");
sol::function g = lua["g"];
sol::environment env_g(lua, sol::create);
env_g.set_on(g);
@ -35,7 +36,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::object global_test = lua["test"];
REQUIRE(!global_test.valid());
lua.script("h = function() end");
lua.safe_script("h = function() end");
lua.set_function("check_f_env",
[&lua, &env_f](sol::object target) {
@ -67,9 +68,9 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
);
REQUIRE_NOTHROW([&lua]() {
lua.script("check_f_env(f)");
lua.script("check_g_env(g)");
lua.script("check_h_env(h)");
lua.safe_script("check_f_env(f)");
lua.safe_script("check_g_env(g)");
lua.safe_script("check_h_env(h)");
}());
}
@ -80,7 +81,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
SECTION("no fallback") {
sol::environment plain_env(lua, sol::create);
lua.script("a = 24", plain_env);
lua.safe_script("a = 24", plain_env);
sol::optional<int> maybe_env_a = plain_env["a"];
sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = plain_env["b"];
@ -96,7 +97,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
}
SECTION("fallback") {
sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua.script("a = 56", env_with_fallback, sol::script_default_on_error);
lua.safe_script("a = 56", env_with_fallback, sol::script_default_on_error);
sol::optional<int> maybe_env_a = env_with_fallback["a"];
sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env_with_fallback["b"];
@ -115,7 +116,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua["env"] = env_with_fallback;
sol::environment env = lua["env"];
lua.script("a = 56", env, sol::script_default_on_error);
lua.safe_script("a = 56", env, sol::script_default_on_error);
sol::optional<int> maybe_env_a = env["a"];
sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env["b"];
@ -133,7 +134,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
SECTION("name with newtable") {
lua["blank_env"] = sol::new_table(0, 1);
sol::environment plain_env = lua["blank_env"];
lua.script("a = 24", plain_env);
lua.safe_script("a = 24", plain_env);
sol::optional<int> maybe_env_a = plain_env["a"];
sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = plain_env["b"];
@ -154,7 +155,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("basic") {
sol::state lua;
lua.script("a = function() return 5 end");
lua.safe_script("a = function() return 5 end");
sol::function a = lua["a"];
@ -170,7 +171,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("return environment value") {
sol::state lua;
lua.script("a = function() return test end");
lua.safe_script("a = function() return test end");
sol::function a = lua["a"];
sol::environment env(lua, sol::create);
@ -184,7 +185,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("set environment value") {
sol::state lua;
lua.script("a = function() test = 5 end");
lua.safe_script("a = function() test = 5 end");
sol::function a = lua["a"];
sol::environment env(lua, sol::create);
@ -220,7 +221,7 @@ TEST_CASE("environments/this_environment", "test various situations of pulling o
lua["x"] = 5;
e["x"] = 20;
SECTION("from Lua script") {
int value = lua.script(code, e);
int value = lua.safe_script(code, e);
REQUIRE(value == 30);
}
SECTION("from C++") {

236
test_filters.cpp Normal file
View File

@ -0,0 +1,236 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>
#include <string>
TEST_CASE("filters/self", "ensure we return a direct reference to the lua userdata rather than creating a new one") {
struct vec2 {
float x = 20.f;
float y = 20.f;
vec2& normalize() {
float len2 = x * x + y * y;
if (len2 != 0) {
float len = sqrtf(len2);
x /= len;
y /= len;
}
return *this;
}
~vec2() {
x = std::numeric_limits<float>::lowest();
y = std::numeric_limits<float>::lowest();
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<vec2>("vec2",
"x", &vec2::x,
"y", &vec2::y,
"normalize", sol::filters(&vec2::normalize, sol::returns_self())
);
REQUIRE_NOTHROW([&]() {
lua.safe_script(R"(
v1 = vec2.new()
print('v1:', v1.x, v1.y)
v2 = v1:normalize()
print('v1:', v1.x, v1.y)
print('v2:', v2.x, v2.y)
print(v1, v2)
assert(rawequal(v1, v2))
v1 = nil
collectgarbage()
print(v2) -- v2 points to same, is not destroyed
)");
}());
}
TEST_CASE("filters/self_dependency", "ensure we can keep a userdata instance alive by attaching it to the lifetime of another userdata") {
struct dep;
struct gc_test;
static std::vector<dep*> deps_destroyed;
static std::vector<gc_test*> gc_tests_destroyed;
struct dep {
int value = 20;
~dep() {
std::cout << "\t" << "[C++] ~dep" << std::endl;
value = std::numeric_limits<int>::max();
deps_destroyed.push_back(this);
}
};
struct gc_test {
dep d;
~gc_test() {
std::cout << "\t" << "[C++] ~gc_test" << std::endl;
gc_tests_destroyed.push_back(this);
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<dep>("dep",
"value", &dep::value,
sol::meta_function::to_string, [](dep& d) {
return "{ " + std::to_string(d.value) + " }";
}
);
lua.new_usertype<gc_test>("gc_test",
"d", sol::filters(&gc_test::d, sol::self_dependency()),
sol::meta_function::to_string, [](gc_test& g) {
return "{ d: { " + std::to_string(g.d.value) + " } }";
}
);
lua.safe_script(R"(
g = gc_test.new()
d = g.d
print("new gc_test, d = g.d")
print("", g)
)");
REQUIRE(deps_destroyed.empty());
REQUIRE(gc_tests_destroyed.empty());
gc_test* g = lua["g"];
dep* d = lua["d"];
lua.safe_script(R"(
print("g = nil, collectgarbage")
g = nil
collectgarbage()
print("", d)
)");
REQUIRE(deps_destroyed.empty());
REQUIRE(gc_tests_destroyed.empty());
lua.safe_script(R"(
print("d = nil, collectgarbage")
d = nil
collectgarbage()
)");
REQUIRE(deps_destroyed.size() == 1);
REQUIRE(gc_tests_destroyed.size() == 1);
REQUIRE(deps_destroyed[0] == d);
REQUIRE(gc_tests_destroyed[0] == g);
}
TEST_CASE("filters/stack_dependencies", "ensure we can take dependencies even to arguments pushed on the stack") {
struct holder;
struct depends_on_reference;
struct composition_related;
static std::vector<composition_related*> composition_relateds_destroyed;
static std::vector<holder*> holders_destroyed;
static std::vector<depends_on_reference*> depends_on_references_destroyed;
struct composition_related {
std::string text = "bark";
~composition_related() {
std::cout << "[C++] ~composition_related" << std::endl;
text = "";
composition_relateds_destroyed.push_back(this);
}
};
struct holder {
int value = 20;
~holder() {
std::cout << "[C++] ~holder" << std::endl;
value = std::numeric_limits<int>::max();
holders_destroyed.push_back(this);
}
};
struct depends_on_reference {
std::reference_wrapper<holder> href;
composition_related comp;
depends_on_reference(holder& h) : href(h) {}
~depends_on_reference() {
std::cout << "[C++] ~depends_on_reference" << std::endl;
depends_on_references_destroyed.push_back(this);
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<holder>("holder",
"value", &holder::value
);
lua.new_usertype<depends_on_reference>("depends_on_reference",
"new", sol::filters(sol::constructors<depends_on_reference(holder&)>(), sol::stack_dependencies(-1, 1)),
"comp", &depends_on_reference::comp
);
lua.safe_script(R"(
h = holder.new()
dor = depends_on_reference.new(h)
c = dor.comp
)");
REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty());
holder* h = lua["h"];
composition_related* c = lua["c"];
depends_on_reference* dor = lua["dor"];
REQUIRE(h == &dor->href.get());
REQUIRE(c == &dor->comp);
lua.safe_script(R"(
h = nil
collectgarbage()
)");
REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty());
lua.safe_script(R"(
c = nil
collectgarbage()
)");
REQUIRE(composition_relateds_destroyed.empty());
REQUIRE(holders_destroyed.empty());
REQUIRE(depends_on_references_destroyed.empty());
lua.safe_script(R"(
dor = nil
collectgarbage()
)");
REQUIRE(composition_relateds_destroyed.size() == 1);
REQUIRE(holders_destroyed.size() == 1);
REQUIRE(depends_on_references_destroyed.size() == 1);
REQUIRE(composition_relateds_destroyed[0] == c);
REQUIRE(holders_destroyed[0] == h);
REQUIRE(depends_on_references_destroyed[0] == dor);
}
int always_return_24(lua_State* L, int) {
return sol::stack::push(L, 24);
}
TEST_CASE("filters/custom", "ensure we can return dependencies on multiple things in the stack") {
sol::state lua;
lua.set_function("f", sol::filters([]() { return std::string("hi there"); }, always_return_24));
int value = lua["f"]();
REQUIRE(value == 24);
}

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <iostream>
#include "test_stack_guard.hpp"
@ -105,7 +107,7 @@ static int raw_noexcept_function(lua_State* L) noexcept {
TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered properly") {
sol::state lua;
lua.script("function f() return '3', 4 end");
lua.safe_script("function f() return '3', 4 end");
std::tuple<std::string, int> result = lua["f"]();
auto s = std::get<0>(result);
@ -119,28 +121,28 @@ 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.script("x = non_overloaded(1, 2, 3)\nprint(x)"));
REQUIRE_NOTHROW(lua.safe_script("x = non_overloaded(1, 2, 3)\nprint(x)"));
/*
// Cannot reasonably support: clang++ refuses to try enough
// deductions to make this work
lua.set_function<int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.script("print(overloaded(1))"));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))"));
lua.set_function<int, int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))"));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))"));
lua.set_function<int, int, int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))"));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2, 3))"));
*/
lua.set_function("overloaded", sol::resolve<int(int)>(overloaded));
REQUIRE_NOTHROW(lua.script("print(overloaded(1))"));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))"));
lua.set_function("overloaded", sol::resolve<int(int, int)>(overloaded));
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))"));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))"));
lua.set_function("overloaded", sol::resolve<int(int, int, int)>(overloaded));
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))"));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2, 3))"));
}
TEST_CASE("functions/return order and multi get", "Check if return order is in the same reading order specified in Lua") {
@ -154,7 +156,7 @@ TEST_CASE("functions/return order and multi get", "Check if return order is in t
lua.set_function("h", []() {
return std::make_tuple(10, 10.0f);
});
lua.script("function g() return 10, 11, 12 end\nx,y,z = g()");
lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()");
auto tcpp = lua.get<sol::function>("f").call<int, int, int>();
auto tlua = lua.get<sol::function>("g").call<int, int, int>();
auto tcpp2 = lua.get<sol::function>("h").call<int, float>();
@ -180,7 +182,7 @@ TEST_CASE("functions/deducing return order and multi get", "Check if return orde
lua.set_function("f", [] {
return std::make_tuple(10, 11, 12);
});
lua.script("function g() return 10, 11, 12 end\nx,y,z = g()");
lua.safe_script("function g() return 10, 11, 12 end\nx,y,z = g()");
std::tuple<int, int, int> tcpp = lua.get<sol::function>("f")();
std::tuple<int, int, int> tlua = lua.get<sol::function>("g")();
std::tuple<int, int, int> tluaget = lua.get<int, int, int>("x", "y", "z");
@ -197,7 +199,7 @@ TEST_CASE("functions/optional values", "check if optionals can be passed in to b
int v;
};
sol::state lua;
lua.script(R"( function f (a)
lua.safe_script(R"( function f (a)
return a
end )");
@ -217,7 +219,7 @@ TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference a
sol::state lua;
lua.new_usertype<A>("A",
"bark", &A::bark);
lua.script(R"( function f (num_value, a)
lua.safe_script(R"( function f (num_value, a)
return num_value * 2, a:bark()
end
function h (num_value, a, b)
@ -259,10 +261,10 @@ TEST_CASE("functions/sol::function to std::function", "check if conversion to st
lua.set_function("testFunc", test_free_func);
lua.set_function("testFunc2", test_free_func2);
lua.script(
lua.safe_script(
"testFunc(function() print(\"hello std::function\") end)"
);
REQUIRE_NOTHROW(lua.script(
REQUIRE_NOTHROW(lua.safe_script(
"function m(a)\n"
" print(\"hello std::function with arg \", a)\n"
" return a\n"
@ -278,7 +280,7 @@ TEST_CASE("functions/returning functions from C++", "check to see if returning a
lua.set_function("makefn", makefn);
lua.set_function("takefn", takefn);
lua.script("afx = makefn()\n"
lua.safe_script("afx = makefn()\n"
"print(afx())\n"
"takefn(afx)\n");
}
@ -308,7 +310,7 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
return handlederrormessage;
};
lua.set_function("cpphandler", cpphandlerfx);
lua.script(
lua.safe_script(
std::string("function luahandler ( message )")
+ " print('lua handler called with: ' .. message)"
+ " return '" + handlederrormessage + "'"
@ -392,85 +394,6 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
}
}
TEST_CASE("functions/destructor tests", "Show that proper copies / destruction happens") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
static void* static_call = reinterpret_cast<void*>(0x01);
typedef void(*fptr)();
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
void func() { last_call = static_cast<void*>(this); };
~x() { ++destroyed; }
};
struct y {
y() { ++created; }
y(const x&) { ++created; }
y(x&&) { ++created; }
y& operator=(const x&) { return *this; }
y& operator=(x&&) { return *this; }
static void func() { last_call = static_call; };
void operator()() { func(); }
operator fptr () { return func; }
~y() { ++destroyed; }
};
// stateful functors/member functions should always copy unless specified
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
x x1;
lua.set_function("x1copy", &x::func, x1);
lua.script("x1copy()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1);
lua.set_function("x1ref", &x::func, std::ref(x1));
lua.script("x1ref()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE(last_call == &x1);
}
REQUIRE(created == 2);
REQUIRE(destroyed == 2);
}
// things convertible to a static function should _never_ be forced to make copies
// therefore, pass through untouched
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
y y1;
lua.set_function("y1copy", y1);
lua.script("y1copy()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
last_call = nullptr;
lua.set_function("y1ref", std::ref(y1));
lua.script("y1ref()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
}
TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") {
sol::state lua;
@ -531,12 +454,12 @@ TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure the
lua.set_function("m", &test_2::a, &t2);
lua.set_function("n", sol::c_call<decltype(&non_overloaded), &non_overloaded>);
lua.script(R"(
lua.safe_script(R"(
o1 = test_1.new()
o2 = test_2.new()
)");
lua.script(R"(
lua.safe_script(R"(
ob = o1:bark()
A = a()
@ -551,32 +474,32 @@ I = i(o1)
)");
lua.script(R"(
lua.safe_script(R"(
J0 = j()
j(24)
J1 = j()
)");
lua.script(R"(
lua.safe_script(R"(
K0 = k(o2)
k(o2, 1024)
K1 = k(o2)
)");
lua.script(R"(
lua.safe_script(R"(
L0 = l(o1)
l(o1, 678)
L1 = l(o1)
)");
lua.script(R"(
lua.safe_script(R"(
M0 = m()
m(256)
M1 = m()
)");
lua.script(R"(
lua.safe_script(R"(
N = n(1, 2, 3)
)");
int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N;
@ -677,9 +600,9 @@ 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.script("function my_add(i, j, k) return i + j + k end"));
REQUIRE_NOTHROW(lua.safe_script("function my_add(i, j, k) return i + j + k end"));
auto f = lua.get<sol::function>("my_add");
REQUIRE_NOTHROW(lua.script("function my_nothing(i, j, k) end"));
REQUIRE_NOTHROW(lua.safe_script("function my_nothing(i, j, k) end"));
auto fvoid = lua.get<sol::function>("my_nothing");
REQUIRE_NOTHROW([&]() {
fvoid(1, 2, 3);
@ -699,7 +622,7 @@ TEST_CASE("simple/call c++ function", "C++ function is called from lua") {
sol::state lua;
lua.set_function("plop_xyz", sep::plop_xyz);
lua.script("x = plop_xyz(2, 6, 'hello')");
lua.safe_script("x = plop_xyz(2, 6, 'hello')");
REQUIRE(lua.get<int>("x") == 11);
}
@ -711,7 +634,7 @@ TEST_CASE("simple/call lambda", "A C++ lambda is exposed to lua and called") {
lua.set_function("foo", [&a] { a = 1; });
lua.script("foo()");
lua.safe_script("foo()");
REQUIRE(a == 1);
}
@ -795,7 +718,7 @@ TEST_CASE("advanced/call lambdas", "A C++ lambda is exposed to lua and called")
return 0;
});
lua.script("set_x(9)");
lua.safe_script("set_x(9)");
REQUIRE(x == 9);
}
@ -816,8 +739,8 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
};
lua.set_function("set_y", &decltype(objy)::operator(), std::ref(objy));
lua.script("set_x(9)");
lua.script("set_y(9)");
lua.safe_script("set_x(9)");
lua.safe_script("set_y(9)");
REQUIRE(x == 9);
REQUIRE(y == 9);
}
@ -825,7 +748,7 @@ TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/ref
TEST_CASE("functions/tie", "make sure advanced syntax with 'tie' works") {
sol::state lua;
lua.script(R"(function f ()
lua.safe_script(R"(function f ()
return 1, 2, 3
end)");
sol::function f = lua["f"];
@ -846,7 +769,7 @@ TEST_CASE("functions/overloading", "Check if overloading works properly for regu
const std::string string_bark = "string: bark";
REQUIRE_NOTHROW(lua.script(
REQUIRE_NOTHROW(lua.safe_script(
"a = func(1)\n"
"b = func('bark')\n"
"c = func(1,2)\n"
@ -868,11 +791,11 @@ TEST_CASE("overloading/c_call", "Make sure that overloading works with c_call fu
lua.set("h", sol::c_call<decltype(&f2), &f2>);
lua.set("obj", fer());
lua.script("r1 = f(1)");
lua.script("r2 = f(1, 2)");
lua.script("r3 = f(obj, 1, 2)");
lua.script("r4 = g(1)");
lua.script("r5 = h(1, 2)");
lua.safe_script("r1 = f(1)");
lua.safe_script("r2 = f(1, 2)");
lua.safe_script("r3 = f(obj, 1, 2)");
lua.safe_script("r4 = g(1)");
lua.safe_script("r5 = h(1, 2)");
int r1 = lua["r1"];
int r2 = lua["r2"];
@ -892,8 +815,8 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::string);
lua.script("function ErrorHandler(msg) print('Lua created error msg : ' .. msg) return msg end");
lua.script("function stringtest(a) if a == nil then error('fuck') end print('Lua recieved content : ' .. a) return a end");
lua.safe_script("function ErrorHandler(msg) print('Lua created error msg : ' .. msg) return msg end");
lua.safe_script("function stringtest(a) if a == nil then error('fuck') end print('Lua recieved content : ' .. a) return a end");
// test normal function
{
@ -941,48 +864,9 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
REQUIRE(sg.check_stack());
}
TEST_CASE("functions/same type closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
static std::set<void*> last_my_closures;
static bool checking_closures = false;
static bool check_failed = false;
struct my_closure {
int& n;
my_closure(int& n) : n(n) {}
~my_closure() noexcept(false) {
if (!checking_closures)
return;
void* addr = static_cast<void*>(this);
auto f = last_my_closures.find(addr);
if (f != last_my_closures.cend()) {
check_failed = true;
}
last_my_closures.insert(f, addr);
}
int operator() () {
++n; return n;
}
};
int n = 250;
my_closure a(n);
my_closure b(n);
{
sol::state lua;
lua.set_function("f", a);
lua.set_function("g", b);
checking_closures = true;
}
REQUIRE_FALSE(check_failed);
REQUIRE(last_my_closures.size() == 2);
}
TEST_CASE("functions/stack multi-return", "Make sure the stack is protected after multi-returns") {
sol::state lua;
lua.script("function f () return 1, 2, 3, 4, 5 end");
lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
{
sol::stack_guard sg(lua);
@ -1005,7 +889,7 @@ TEST_CASE("functions/stack multi-return", "Make sure the stack is protected afte
TEST_CASE("functions/protected stack multi-return", "Make sure the stack is protected after multi-returns") {
sol::state lua;
lua.script("function f () return 1, 2, 3, 4, 5 end");
lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
{
sol::stack_guard sg(lua);
@ -1030,8 +914,8 @@ TEST_CASE("functions/function_result as arguments", "ensure that function_result
sol::state lua;
lua.open_libraries();
lua.script("function f () return 1, 2, 3, 4, 5 end");
lua.script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{
sol::stack_guard sg(lua);
@ -1059,8 +943,8 @@ TEST_CASE("functions/protected_function_result as arguments", "ensure that prote
sol::state lua;
lua.open_libraries();
lua.script("function f () return 1, 2, 3, 4, 5 end");
lua.script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{
sol::stack_guard sg(lua);
@ -1091,9 +975,9 @@ TEST_CASE("functions/overloaded variadic", "make sure variadics work to some deg
sol::table ssl = lua.create_named_table("ssl");
ssl.set_function("test", sol::overload(&va_func<int>, &va_func<double>));
lua.script("a = ssl.test(1, 2, 3)");
lua.script("b = ssl.test(1, 2)");
lua.script("c = ssl.test(2.2)");
lua.safe_script("a = ssl.test(1, 2, 3)");
lua.safe_script("b = ssl.test(1, 2)");
lua.safe_script("c = ssl.test(2.2)");
int a = lua["a"];
int b = lua["b"];
@ -1117,20 +1001,20 @@ TEST_CASE("functions/sectioning variadic", "make sure variadics can bite off chu
return r;
});
lua.script("x = f(1, 2, 3, 4)");
lua.script("x2 = f(8, 200, 3, 4)");
lua.script("x3 = f(1, 2, 3, 4, 5, 6)");
lua.safe_script("x = f(1, 2, 3, 4)");
lua.safe_script("x2 = f(8, 200, 3, 4)");
lua.safe_script("x3 = f(1, 2, 3, 4, 5, 6)");
lua.script("print(x) assert(x == 7)");
lua.script("print(x2) assert(x2 == 7)");
lua.script("print(x3) assert(x3 == 18)");
lua.safe_script("print(x) assert(x == 7)");
lua.safe_script("print(x2) assert(x2 == 7)");
lua.safe_script("print(x3) assert(x3 == 18)");
}
TEST_CASE("functions/set_function already wrapped", "setting a function returned from Lua code that is already wrapped into a sol::function or similar") {
SECTION("test different types") {
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end");
sol::function fn = lua.safe_script("return function() return 5 end");
sol::protected_function pfn = fn;
std::function<int()> sfn = fn;
@ -1138,23 +1022,23 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
lua.set_function("test2", pfn);
lua.set_function("test3", sfn);
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test() == 5)"));
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)"));
REQUIRE_NOTHROW(lua.script("assert(type(test2) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test2() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test2() == 5)"));
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)"));
REQUIRE_NOTHROW(lua.script("assert(type(test3) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test3() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test3() == 5)"));
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)"));
}
SECTION("getting the value from C++") {
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end");
sol::function fn = lua.safe_script("return function() return 5 end");
int result = fn();
REQUIRE(result == 5);
@ -1163,13 +1047,13 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
SECTION("setting the function directly") {
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end");
sol::function fn = lua.safe_script("return function() return 5 end");
lua.set_function("test", fn);
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test() == 5)"));
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)"));
}
@ -1177,23 +1061,23 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::function fn2 = lua.script("return function() print('this was executed') end");
sol::function fn2 = lua.safe_script("return function() print('this was executed') end");
lua.set_function("test", fn2);
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("test()"));
REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("test()"));
}
SECTION("setting the function indirectly, with the return value cast explicitly") {
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::function fn = lua.script("return function() return 5 end");
sol::function fn = lua.safe_script("return function() return 5 end");
lua.set_function("test", [&fn]() { return fn.call<int>(); });
REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.script("assert(test() == 5)"));
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)"));
}
}
@ -1252,15 +1136,15 @@ TEST_CASE("functions/pointer nullptr + nil", "ensure specific semantics for hand
lua["h"] = &nil_test::h;
REQUIRE_NOTHROW([&]() {
lua.script("f(v1)");
lua.script("f(v2)");
lua.script("f(v3)");
lua.script("f(v4)");
lua.safe_script("f(v1)");
lua.safe_script("f(v2)");
lua.safe_script("f(v3)");
lua.safe_script("f(v4)");
lua.script("assert(v1 == nil)");
lua.script("assert(v2 == nil)");
lua.script("assert(v3 == nil)");
lua.script("assert(v4 == nil)");
lua.safe_script("assert(v1 == nil)");
lua.safe_script("assert(v2 == nil)");
lua.safe_script("assert(v3 == nil)");
lua.safe_script("assert(v4 == nil)");
}());
}
SECTION("throw unique argument") {
@ -1405,16 +1289,16 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo
lua["v4"] = ut.get();
REQUIRE_NOTHROW([&]() {
lua.script("f(v1)");
lua.script("g(v1)");
lua.script("g(v2)");
lua.script("g(v3)");
lua.script("g(v4)");
lua.script("h(v1)");
lua.script("h(v2)");
lua.script("h(v3)");
lua.script("h(v4)");
lua.script("i(20, v1)");
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)");
}());
};
// LuaJIT segfaults hard on some Linux machines
@ -1473,14 +1357,14 @@ TEST_CASE("functions/noexcept", "allow noexcept functions to be serialized prope
lua.set_function("m", ccall);
lua["t"] = T();
lua.script("v1 = f()");
lua.script("v2 = g(t)");
lua.script("v3 = h()");
lua.script("v4 = i()");
lua.script("v5 = j()");
lua.script("v6 = k()");
lua.script("v7 = l()");
lua.script("v8 = m()");
lua.safe_script("v1 = f()");
lua.safe_script("v2 = g(t)");
lua.safe_script("v3 = h()");
lua.safe_script("v4 = i()");
lua.safe_script("v5 = j()");
lua.safe_script("v6 = k()");
lua.safe_script("v7 = l()");
lua.safe_script("v8 = m()");
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];

504
test_gc.cpp Normal file
View File

@ -0,0 +1,504 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <memory>
TEST_CASE("gc/destructors", "test if destructors are fired properly through gc of unbound usertypes") {
struct test;
static std::vector<test*> tests_destroyed;
struct test {
int v = 10;
~test() {
tests_destroyed.push_back(this);
}
};
test t;
test* pt = nullptr;
{
sol::state lua;
lua["t"] = test{};
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 2);
REQUIRE(tests_destroyed.back() == pt);
{
sol::state lua;
lua["t"] = &t;
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 2);
REQUIRE(&t == pt);
{
sol::state lua;
lua["t"] = std::ref(t);
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 2);
REQUIRE(&t == pt);
{
sol::state lua;
lua["t"] = t;
pt = lua["t"];
}
REQUIRE(tests_destroyed.size() == 3);
REQUIRE(&t != pt);
REQUIRE(nullptr != pt);
}
TEST_CASE("gc/function argument storage", "ensure functions take references on their types, not ownership, when specified") {
class gc_entity;
static std::vector<gc_entity*> entities;
class gc_entity {
public:
~gc_entity() { entities.push_back(this); }
};
SECTION("plain") {
entities.clear();
sol::state lua;
lua.open_libraries();
sol::function f = lua.safe_script(R"(
return function(e)
end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
SECTION("regular") {
entities.clear();
sol::state lua;
lua.open_libraries();
lua.new_usertype<gc_entity>("entity");
sol::function f = lua.safe_script(R"(
return function(e)
end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
SECTION("simple") {
entities.clear();
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<gc_entity>("entity");
sol::function f = lua.safe_script(R"(
return function(e)
end
)");
gc_entity* target = nullptr;
{
gc_entity e;
target = &e;
{
f(e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(&e); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
{
f(std::ref(e)); // same with std::ref(e)!
lua.collect_garbage(); // destroys e for some reason
}
}
REQUIRE(entities.size() == 1);
REQUIRE(entities.back() == target);
}
}
TEST_CASE("gc/function storage", "show that proper copies / destruction happens for function storage (or not)") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
static void* static_call = reinterpret_cast<void*>(0x01);
typedef void(*fptr)();
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
void func() { last_call = static_cast<void*>(this); };
~x() { ++destroyed; }
};
struct y {
y() { ++created; }
y(const x&) { ++created; }
y(x&&) { ++created; }
y& operator=(const x&) { return *this; }
y& operator=(x&&) { return *this; }
static void func() { last_call = static_call; };
void operator()() { func(); }
operator fptr () { return func; }
~y() { ++destroyed; }
};
// stateful functors/member functions should always copy unless specified
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
x x1;
lua.set_function("x1copy", &x::func, x1);
lua.safe_script("x1copy()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(last_call == &x1);
lua.set_function("x1ref", &x::func, std::ref(x1));
lua.safe_script("x1ref()");
REQUIRE(created == 2);
REQUIRE(destroyed == 0);
REQUIRE(last_call == &x1);
}
REQUIRE(created == 2);
REQUIRE(destroyed == 2);
}
// things convertible to a static function should _never_ be forced to make copies
// therefore, pass through untouched
{
created = 0;
destroyed = 0;
last_call = nullptr;
{
sol::state lua;
y y1;
lua.set_function("y1copy", y1);
lua.safe_script("y1copy()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
last_call = nullptr;
lua.set_function("y1ref", std::ref(y1));
lua.safe_script("y1ref()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE(last_call == static_call);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
}
TEST_CASE("gc/same type closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
static std::set<void*> last_my_closures;
static bool checking_closures = false;
static bool check_failed = false;
struct my_closure {
int& n;
my_closure(int& n) : n(n) {}
~my_closure() noexcept(false) {
if (!checking_closures)
return;
void* addr = static_cast<void*>(this);
auto f = last_my_closures.find(addr);
if (f != last_my_closures.cend()) {
check_failed = true;
}
last_my_closures.insert(f, addr);
}
int operator() () {
++n; return n;
}
};
int n = 250;
my_closure a(n);
my_closure b(n);
{
sol::state lua;
lua.set_function("f", a);
lua.set_function("g", b);
checking_closures = true;
}
REQUIRE_FALSE(check_failed);
REQUIRE(last_my_closures.size() == 2);
}
TEST_CASE("gc/usertypes", "show that proper copies / destruction happens for usertypes") {
static int created = 0;
static int destroyed = 0;
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
~x() { ++destroyed; }
};
SECTION("plain") {
created = 0;
destroyed = 0;
{
sol::state lua;
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
SECTION("regular") {
created = 0;
destroyed = 0;
{
sol::state lua;
lua.new_usertype<x>("x");
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
SECTION("simple") {
created = 0;
destroyed = 0;
{
sol::state lua;
lua.new_simple_usertype<x>("x");
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
}
TEST_CASE("gc/double-deletion tests", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
class crash_class {
public:
crash_class() {}
~crash_class() { a = 10; }
private:
int a;
};
sol::state lua;
SECTION("regular") {
lua.new_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.safe_script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
SECTION("simple") {
lua.new_simple_usertype<crash_class>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.safe_script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
}
TEST_CASE("gc/shared_ptr regression", "metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
test() {
++created;
}
~test() {
++destroyed;
}
};
SECTION("regular") {
created = 0;
destroyed = 0;
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.safe_script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
SECTION("simple") {
created = 0;
destroyed = 0;
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.safe_script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
}
TEST_CASE("gc/double deleter guards", "usertype metatables internally must not rely on C++ state") {
SECTION("regular") {
struct c_a { int xv; };
struct c_b { int yv; };
auto routine = []() {
sol::state lua;
lua.new_usertype<c_a>("c_a", "x", &c_a::xv);
lua.new_usertype<c_b>("c_b", "y", &c_b::yv);
lua = sol::state();
lua.new_usertype<c_a>("c_a", "x", &c_a::xv);
lua.new_usertype<c_b>("c_b", "y", &c_b::yv);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
SECTION("simple") {
struct sc_a { int xv; };
struct sc_b { int yv; };
auto routine = []() {
sol::state lua;
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
lua = sol::state();
lua.new_simple_usertype<sc_a>("c_a", "x", &sc_a::xv);
lua.new_simple_usertype<sc_b>("c_b", "y", &sc_b::yv);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
}

View File

@ -42,14 +42,14 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
sol::base_classes, sol::bases<C, B, A>()
);
lua.script("obj = D.new()");
lua.script("d = obj:d()");
lua.safe_script("obj = D.new()");
lua.safe_script("d = obj:d()");
bool d = lua["d"];
lua.script("c = obj.c");
lua.safe_script("c = obj.c");
double c = lua["c"];
lua.script("b = obj:b()");
lua.safe_script("b = obj:b()");
int b = lua["b"];
lua.script("a = obj.a");
lua.safe_script("a = obj.a");
int a = lua["a"];
REQUIRE(d);
@ -124,19 +124,19 @@ TEST_CASE("inheritance/multi base", "test that multiple bases all work and overl
lua.set_usertype("TestClass03", s_TestUsertype03);
lua.script(R"(
lua.safe_script(R"(
tc0 = TestClass00()
)");
lua.script(R"(
lua.safe_script(R"(
tc2 = TestClass02(tc0)
)");
lua.script(R"(
lua.safe_script(R"(
tc1 = TestClass01()
)");
lua.script(R"(
lua.safe_script(R"(
tc3 = TestClass03(tc1)
)");
@ -219,19 +219,19 @@ TEST_CASE("inheritance/simple multi base", "test that multiple bases all work an
lua.set_usertype("TestClass03", s_TestUsertype03);
lua.script(R"(
lua.safe_script(R"(
tc0 = TestClass00()
)");
lua.script(R"(
lua.safe_script(R"(
tc2 = TestClass02(tc0)
)");
lua.script(R"(
lua.safe_script(R"(
tc1 = TestClass01()
)");
lua.script(R"(
lua.safe_script(R"(
tc3 = TestClass03(tc1)
)");

View File

@ -12,8 +12,8 @@ TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") {
REQUIRE(num == true);
return num;
});
lua.script("x = f(true)");
lua.script("assert(x == true)");
lua.safe_script("x = f(true)");
lua.safe_script("assert(x == true)");
sol::object x = lua["x"];
REQUIRE(x.is<bool>());
REQUIRE(x.as<bool>() == true);
@ -32,8 +32,8 @@ TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and
REQUIRE(num == 0xFFFFFFFF);
return num;
});
lua.script("x = f(0xFFFFFFFF)");
lua.script("assert(x == 0xFFFFFFFF)");
lua.safe_script("x = f(0xFFFFFFFF)");
lua.safe_script("assert(x == 0xFFFFFFFF)");
sol::object x = lua["x"];
REQUIRE(x.is<T>());
REQUIRE(x.as<T>() == 0xFFFFFFFF);
@ -47,8 +47,8 @@ TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and fr
REQUIRE(num == 0x1FFFFFFFFFFFFFull);
return num;
});
lua.script("x = f(0x1FFFFFFFFFFFFF)");
lua.script("assert(x == 0x1FFFFFFFFFFFFF)");
lua.safe_script("x = f(0x1FFFFFFFFFFFFF)");
lua.safe_script("assert(x == 0x1FFFFFFFFFFFFF)");
sol::object x = lua["x"];
REQUIRE(x.is<T>());
REQUIRE(x.as<T>() == 0x1FFFFFFFFFFFFFull);
@ -83,10 +83,10 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
});
//signed 32bit
REQUIRE_NOTHROW([&lua]() {
lua.script("x = s32(-1)");
lua.script("assert(x == -1)");
lua.script("x = s32(0xFFFFFFFF)");
lua.script("assert(x == -1)");
lua.safe_script("x = s32(-1)");
lua.safe_script("assert(x == -1)");
lua.safe_script("x = s32(0xFFFFFFFF)");
lua.safe_script("assert(x == -1)");
sol::object x = lua["x"];
REQUIRE(x.is<std::int32_t>());
REQUIRE(x.as<std::int32_t>() == -1);
@ -95,10 +95,10 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
}());
//unsigned 32bit
REQUIRE_NOTHROW([&lua]() {
lua.script("x = u32(0xFFFFFFFF)");
lua.script("assert(x == 0xFFFFFFFF)");
lua.script("x = u32(-1)");
lua.script("assert(x == 0xFFFFFFFF)");
lua.safe_script("x = u32(0xFFFFFFFF)");
lua.safe_script("assert(x == 0xFFFFFFFF)");
lua.safe_script("x = u32(-1)");
lua.safe_script("assert(x == 0xFFFFFFFF)");
sol::object x = lua["x"];
REQUIRE(x.is<std::int32_t>());
REQUIRE(x.as<std::int32_t>() == -1);
@ -107,8 +107,8 @@ TEST_CASE("large_integer/double", "pass negative and large positive values as si
}());
//signed 64bit
REQUIRE_NOTHROW([&lua]() {
lua.script("x = s64(-1)");
lua.script("assert(x == -1)");
lua.safe_script("x = s64(-1)");
lua.safe_script("assert(x == -1)");
sol::object x = lua["x"];
REQUIRE(x.is<std::int64_t>());
REQUIRE(x.as<std::int64_t>() == -1);

View File

@ -47,6 +47,43 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
lua["v2"] = &v2;
lua["v3"] = &v3;
SECTION("plain") {
// Can only compare identity here
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(t1 == t1)");
lua.safe_script("assert(t2 == t2)");
lua.safe_script("assert(t3 == t3)");
}());
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(t1 == t2)");
lua.safe_script("assert(not (t1 == t3))");
lua.safe_script("assert(not (t2 == t3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(u1 == u1)");
lua.safe_script("assert(u2 == u2)");
lua.safe_script("assert(u3 == u3)");
}());
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(not (u1 == u2))");
lua.safe_script("assert(u1 == u3)");
lua.safe_script("assert(not (u2 == u3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(v1 == v1)");
lua.safe_script("assert(v2 == v2)");
lua.safe_script("assert(v3 == v3)");
}());
REQUIRE_NOTHROW([&] {
lua.safe_script("assert(not (v1 == v2))");
lua.safe_script("assert(v1 == v3)");
lua.safe_script("assert(not (v2 == v3))");
}());
}
SECTION("regular") {
lua.new_usertype<T>("T");
lua.new_usertype<U>("U");
@ -54,38 +91,38 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
// Can only compare identity here
REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t1)");
lua.script("assert(t2 == t2)");
lua.script("assert(t3 == t3)");
lua.safe_script("assert(t1 == t1)");
lua.safe_script("assert(t2 == t2)");
lua.safe_script("assert(t3 == t3)");
}());
REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t2)");
lua.script("assert(not (t1 == t3))");
lua.script("assert(not (t2 == t3))");
lua.safe_script("assert(t1 == t2)");
lua.safe_script("assert(not (t1 == t3))");
lua.safe_script("assert(not (t2 == t3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.script("assert(u1 == u1)");
lua.script("assert(u2 == u2)");
lua.script("assert(u3 == u3)");
lua.safe_script("assert(u1 == u1)");
lua.safe_script("assert(u2 == u2)");
lua.safe_script("assert(u3 == u3)");
}());
REQUIRE_NOTHROW([&] {
lua.script("assert(not (u1 == u2))");
lua.script("assert(u1 == u3)");
lua.script("assert(not (u2 == u3))");
lua.safe_script("assert(not (u1 == u2))");
lua.safe_script("assert(u1 == u3)");
lua.safe_script("assert(not (u2 == u3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.script("assert(v1 == v1)");
lua.script("assert(v2 == v2)");
lua.script("assert(v3 == v3)");
lua.safe_script("assert(v1 == v1)");
lua.safe_script("assert(v2 == v2)");
lua.safe_script("assert(v3 == v3)");
}());
REQUIRE_NOTHROW([&] {
lua.script("assert(not (v1 == v2))");
lua.script("assert(v1 == v3)");
lua.script("assert(not (v2 == v3))");
lua.safe_script("assert(not (v1 == v2))");
lua.safe_script("assert(v1 == v3)");
lua.safe_script("assert(not (v2 == v3))");
}());
}
SECTION("simple") {
@ -95,38 +132,38 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
// Can only compare identity here
REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t1)");
lua.script("assert(t2 == t2)");
lua.script("assert(t3 == t3)");
lua.safe_script("assert(t1 == t1)");
lua.safe_script("assert(t2 == t2)");
lua.safe_script("assert(t3 == t3)");
}());
REQUIRE_NOTHROW([&] {
lua.script("assert(t1 == t2)");
lua.script("assert(not (t1 == t3))");
lua.script("assert(not (t2 == t3))");
lua.safe_script("assert(t1 == t2)");
lua.safe_script("assert(not (t1 == t3))");
lua.safe_script("assert(not (t2 == t3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.script("assert(u1 == u1)");
lua.script("assert(u2 == u2)");
lua.script("assert(u3 == u3)");
lua.safe_script("assert(u1 == u1)");
lua.safe_script("assert(u2 == u2)");
lua.safe_script("assert(u3 == u3)");
}());
REQUIRE_NOTHROW([&] {
lua.script("assert(not (u1 == u2))");
lua.script("assert(u1 == u3)");
lua.script("assert(not (u2 == u3))");
lua.safe_script("assert(not (u1 == u2))");
lua.safe_script("assert(u1 == u3)");
lua.safe_script("assert(not (u2 == u3))");
}());
// Object should compare equal to themselves
// (and not invoke operator==; pointer test should be sufficient)
REQUIRE_NOTHROW([&] {
lua.script("assert(v1 == v1)");
lua.script("assert(v2 == v2)");
lua.script("assert(v3 == v3)");
lua.safe_script("assert(v1 == v1)");
lua.safe_script("assert(v2 == v2)");
lua.safe_script("assert(v3 == v3)");
}());
REQUIRE_NOTHROW([&] {
lua.script("assert(not (v1 == v2))");
lua.script("assert(v1 == v3)");
lua.script("assert(not (v2 == v3))");
lua.safe_script("assert(not (v1 == v2))");
lua.safe_script("assert(v1 == v3)");
lua.safe_script("assert(not (v2 == v3))");
}());
}
}
@ -134,13 +171,21 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
TEST_CASE("operators/call", "test call operator generation") {
struct callable {
int operator ()(int a, std::string b) {
return a + b.length();
return a + static_cast<int>(b.length());
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua.set("obj", callable());
lua.safe_script("v = obj(2, 'bark woof')");
int v = lua["v"];
REQUIRE(v == 11);
}
}
SECTION("regular") {
lua.new_usertype<callable>("callable");
{
@ -168,13 +213,53 @@ const void* stringable::last_print_ptr = nullptr;
std::ostream& operator<< (std::ostream& ostr, const stringable& o) {
stringable::last_print_ptr = static_cast<const void*>(&o);
return ostr << " { stringable! }";
return ostr << "{ stringable, std::ostream! }";
}
struct adl_stringable {
static const void* last_print_ptr;
};
const void* adl_stringable::last_print_ptr = nullptr;
std::string to_string(const adl_stringable& o) {
adl_stringable::last_print_ptr = static_cast<const void*>(&o);
return "{ adl_stringable, to_string! }";
}
namespace inside {
struct adl_stringable2 {
static const void* last_print_ptr;
};
const void* adl_stringable2::last_print_ptr = nullptr;
std::string to_string(const adl_stringable2& o) {
adl_stringable2::last_print_ptr = static_cast<const void*>(&o);
return "{ inside::adl_stringable2, inside::to_string! }";
}
}
struct member_stringable {
static const void* last_print_ptr;
std::string to_string() const {
member_stringable::last_print_ptr = static_cast<const void*>(this);
return "{ member_stringable, to_string! }";
}
};
const void* member_stringable::last_print_ptr = nullptr;
TEST_CASE("operators/stringable", "test std::ostream stringability") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = stringable();
lua.safe_script("print(obj)");
stringable& obj = lua["obj"];
REQUIRE(stringable::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<stringable>("stringable");
{
@ -195,6 +280,102 @@ TEST_CASE("operators/stringable", "test std::ostream stringability") {
}
}
TEST_CASE("operators/adl_stringable", "test adl to_string stringability") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = adl_stringable();
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<adl_stringable>("stringable");
{
lua["obj"] = adl_stringable();
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
SECTION("simple") {
lua.new_simple_usertype<adl_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
adl_stringable& obj = lua["obj"];
REQUIRE(adl_stringable::last_print_ptr == &obj);
}
}
}
TEST_CASE("operators/inside::adl_stringable2", "test adl to_string stringability from inside a namespace") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = inside::adl_stringable2();
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<inside::adl_stringable2>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
SECTION("simple") {
lua.new_simple_usertype<inside::adl_stringable2>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
inside::adl_stringable2& obj = lua["obj"];
REQUIRE(inside::adl_stringable2::last_print_ptr == &obj);
}
}
}
TEST_CASE("operators/member_stringable", "test member to_string stringability") {
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = member_stringable();
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
SECTION("regular") {
lua.new_usertype<member_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
SECTION("simple") {
lua.new_simple_usertype<member_stringable>("stringable");
{
lua.safe_script("obj = stringable.new()");
lua.safe_script("print(obj)");
member_stringable& obj = lua["obj"];
REQUIRE(member_stringable::last_print_ptr == &obj);
}
}
}
TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") {
#if SOL_LUA_VERSION > 501
struct container {
@ -219,6 +400,14 @@ TEST_CASE("operators/container-like", "test that generic begin/end and iterator
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = container();
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
std::size_t i = lua["i"];
REQUIRE(i == 10);
}
}
SECTION("regular") {
lua.new_usertype<container>("container");
{
@ -252,6 +441,14 @@ TEST_CASE("operators/length", "test that size is automatically bound to the leng
sol::state lua;
lua.open_libraries(sol::lib::base);
SECTION("plain") {
{
lua["obj"] = sizable();
lua.safe_script("s = #obj");
std::size_t s = lua["s"];
REQUIRE(s == 6);
}
}
SECTION("regular") {
lua.new_usertype<sizable>("sizable");
{

View File

@ -6,8 +6,8 @@
TEST_CASE("issues/stack overflow", "make sure various operations repeated don't trigger stack overflow") {
sol::state lua;
lua.script("t = {};t[0]=20");
lua.script("lua_function=function(i)return i;end");
lua.safe_script("t = {};t[0]=20");
lua.safe_script("lua_function=function(i)return i;end");
sol::function f = lua["lua_function"];
std::string teststring = "testtext";

72
test_plain_types.cpp Normal file
View File

@ -0,0 +1,72 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <catch.hpp>
TEST_CASE("plain/alignment", "test that aligned classes in certain compilers don't trigger compiler errors") {
#ifdef _MSC_VER
__declspec(align(16)) class aligned_class {
int var;
};
class A {
aligned_class a;
};
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::math);
lua.new_usertype<A>("A");
A a;
lua["a"] = &a;
A& la = lua["a"];
REQUIRE(&a == &la);
#else
REQUIRE(true);
#endif // VC++ stuff
}
TEST_CASE("plain/indestructible", "test that we error for types that are innately indestructible") {
struct indestructible {
public:
int v = 20;
struct insider {
void operator()(indestructible* i) const {
i->~indestructible();
}
};
private:
~indestructible() {
}
};
SECTION("doomed") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unique_ptr<indestructible, indestructible::insider> i = sol::detail::make_unique_deleter<indestructible, indestructible::insider>();
lua["i"] = *i;
lua.safe_script("i = nil");
auto result = lua.safe_script("collectgarbage()", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
SECTION("saved") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unique_ptr<indestructible, indestructible::insider> i = sol::detail::make_unique_deleter<indestructible, indestructible::insider>();
lua["i"] = *i;
lua.new_usertype<indestructible>("indestructible",
sol::default_constructor,
sol::meta_function::garbage_collect, sol::destructor([](indestructible& i) {
indestructible::insider del;
del(&i);
})
);
lua.safe_script("i = nil");
auto result = lua.safe_script("collectgarbage()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}

View File

@ -49,20 +49,20 @@ TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly wo
"z", sol::overload(&bark::get, &bark::set)
);
lua.script("b = bark.new()");
lua.safe_script("b = bark.new()");
bark& b = lua["b"];
lua.script("b:fun()");
lua.safe_script("b:fun()");
int var = b.var;
REQUIRE(var == 51);
lua.script("b:var(20)");
lua.script("v = b:var()");
lua.safe_script("b:var(20)");
lua.safe_script("v = b:var()");
int v = lua["v"];
REQUIRE(v == 20);
REQUIRE(b.var == 20);
lua.script("m = b:the_marker()");
lua.safe_script("m = b:the_marker()");
marker& m = lua["m"];
REQUIRE_FALSE(b.mark.value);
REQUIRE_FALSE(m.value);
@ -73,16 +73,16 @@ TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly wo
sol::table barktable = lua["bark"];
barktable["special"] = &bark::special;
lua.script("s = b:special()");
lua.safe_script("s = b:special()");
std::string s = lua["s"];
REQUIRE(s == "woof");
lua.script("b:y(24)");
lua.script("x = b:x()");
lua.safe_script("b:y(24)");
lua.safe_script("x = b:x()");
int x = lua["x"];
REQUIRE(x == 24);
lua.script("z = b:z(b:z() + 5)");
lua.safe_script("z = b:z(b:z() + 5)");
int z = lua["z"];
REQUIRE(z == 29);
}
@ -132,23 +132,23 @@ TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with speci
"z", sol::overload(&bark::get, &bark::set)
);
lua.script("bx = bark.new(760)");
lua.safe_script("bx = bark.new(760)");
bark& bx = lua["bx"];
REQUIRE(bx.var == 760);
lua.script("b = bark.new()");
lua.safe_script("b = bark.new()");
bark& b = lua["b"];
lua.script("b:fun()");
lua.safe_script("b:fun()");
int var = b.var;
REQUIRE(var == 51);
lua.script("b:var(20)");
lua.script("v = b:var()");
lua.safe_script("b:var(20)");
lua.safe_script("v = b:var()");
int v = lua["v"];
REQUIRE(v == 20);
lua.script("m = b:the_marker()");
lua.safe_script("m = b:the_marker()");
marker& m = lua["m"];
REQUIRE_FALSE(b.mark.value);
REQUIRE_FALSE(m.value);
@ -159,58 +159,20 @@ TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with speci
sol::table barktable = lua["bark"];
barktable["special"] = &bark::special;
lua.script("s = b:special()");
lua.safe_script("s = b:special()");
std::string s = lua["s"];
REQUIRE(s == "woof");
lua.script("b:y(24)");
lua.script("x = b:x()");
lua.safe_script("b:y(24)");
lua.safe_script("x = b:x()");
int x = lua["x"];
REQUIRE(x == 24);
lua.script("z = b:z(b:z() + 5)");
lua.safe_script("z = b:z(b:z() + 5)");
int z = lua["z"];
REQUIRE(z == 29);
}
TEST_CASE("simple_usertype/shared_ptr regression", "simple usertype metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
test() {
++created;
}
~test() {
++destroyed;
}
};
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values (no ref)") {
int muh_variable = 10;
int through_variable = 25;
@ -228,7 +190,7 @@ TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values
through_variable = 20;
lua.script(R"(
lua.safe_script(R"(
print(test.straight)
s = test.straight
print(test.global)
@ -297,29 +259,29 @@ TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond
B b;
lua.set("b", &b);
lua.script("b:a()");
lua.safe_script("b:a()");
sB sb;
lua.set("sb", &sb);
lua.script("sb:a()");
lua.safe_script("sb:a()");
sV sv;
lua.set("sv", &sv);
lua.script("print(sv.b)assert(sv.b == 20)");
lua.safe_script("print(sv.b)assert(sv.b == 20)");
sW sw;
lua.set("sw", &sw);
lua.script("print(sw.a)assert(sw.a == 10)");
lua.script("print(sw.b)assert(sw.b == 20)");
lua.script("print(sw.pb)assert(sw.pb == 22)");
lua.script("sw.a = 11");
lua.script("sw.b = 21");
lua.script("print(sw.a)assert(sw.a == 11)");
lua.script("print(sw.b)assert(sw.b == 21)");
lua.script("print(sw.pb)assert(sw.pb == 23)");
lua.script("sw.pb = 25");
lua.script("print(sw.b)assert(sw.b == 25)");
lua.script("print(sw.pb)assert(sw.pb == 27)");
lua.safe_script("print(sw.a)assert(sw.a == 10)");
lua.safe_script("print(sw.b)assert(sw.b == 20)");
lua.safe_script("print(sw.pb)assert(sw.pb == 22)");
lua.safe_script("sw.a = 11");
lua.safe_script("sw.b = 21");
lua.safe_script("print(sw.a)assert(sw.a == 11)");
lua.safe_script("print(sw.b)assert(sw.b == 21)");
lua.safe_script("print(sw.pb)assert(sw.pb == 23)");
lua.safe_script("sw.pb = 25");
lua.safe_script("print(sw.b)assert(sw.b == 25)");
lua.safe_script("print(sw.pb)assert(sw.pb == 27)");
}
TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes should invoke the proper factories") {
@ -340,21 +302,30 @@ TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes sho
sol::constructors<sol::types<>, sol::types<const B&>> c;
lua.new_simple_usertype<B>("B",
sol::call_constructor, c,
"new", sol::factories([]() { return B(); }),
"new2", sol::initializers([](B& mem) { new(&mem)B(); }, [](B& mem, int v) { new(&mem)B(); mem.bvar = v; }),
"new", sol::factories([]() {
return B();
}),
"new2", sol::initializers(
[](B& mem) {
new(&mem)B();
},
[](B& mem, int v) {
new(&mem)B(); mem.bvar = v;
}
),
"f", sol::as_function(&B::bvar),
"g", sol::overload([](B&) { return 2; }, [](B&, int v) { return v; })
);
lua.script("b = B()");
lua.script("b2 = B.new()");
lua.script("b3 = B.new2()");
lua.script("b4 = B.new2(11)");
lua.safe_script("b = B()");
lua.safe_script("b2 = B.new()");
lua.safe_script("b3 = B.new2()");
lua.safe_script("b4 = B.new2(11)");
lua.script("x = b:f()");
lua.script("x2 = b2:f()");
lua.script("x3 = b3:f()");
lua.script("x4 = b4:f()");
lua.safe_script("x = b:f()");
lua.safe_script("x2 = b2:f()");
lua.safe_script("x3 = b3:f()");
lua.safe_script("x4 = b4:f()");
int x = lua["x"];
int x2 = lua["x2"];
int x3 = lua["x3"];
@ -364,10 +335,10 @@ TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes sho
REQUIRE(x3 == 24);
REQUIRE(x4 == 11);
lua.script("y = b:g()");
lua.script("y2 = b2:g(3)");
lua.script("y3 = b3:g()");
lua.script("y4 = b4:g(3)");
lua.safe_script("y = b:g()");
lua.safe_script("y2 = b2:g(3)");
lua.safe_script("y3 = b3:g()");
lua.safe_script("y4 = b4:g(3)");
int y = lua["y"];
int y2 = lua["y2"];
int y3 = lua["y3"];
@ -391,53 +362,22 @@ TEST_CASE("simple_usertype/runtime append", "allow extra functions to be appende
lua.set("b", std::make_unique<B>());
lua["A"]["method"] = []() { return 200; };
lua["B"]["method2"] = [](B&) { return 100; };
lua.script("x = b.method()");
lua.script("y = b:method()");
lua.safe_script("x = b.method()");
lua.safe_script("y = b:method()");
int x = lua["x"];
int y = lua["y"];
REQUIRE(x == 200);
REQUIRE(y == 200);
lua.script("z = b.method2(b)");
lua.script("w = b:method2()");
lua.safe_script("z = b.method2(b)");
lua.safe_script("w = b:method2()");
int z = lua["z"];
int w = lua["w"];
REQUIRE(z == 100);
REQUIRE(w == 100);
}
TEST_CASE("simple_usertype/destruction test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
sol::state lua;
class CrashClass {
public:
CrashClass() {
}
~CrashClass() {
a = 10; // This will cause a crash.
}
private:
int a;
};
lua.new_simple_usertype<CrashClass>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") {
struct A {
int func() {
@ -456,9 +396,9 @@ TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta tab
lua.set("pa", &a);
lua.set("ua", std::make_unique<A>());
REQUIRE_NOTHROW([&]{
lua.script("assert(a:func() == 5000)");
lua.script("assert(pa:func() == 5000)");
lua.script("assert(ua:func() == 5000)");
lua.safe_script("assert(a:func() == 5000)");
lua.safe_script("assert(pa:func() == 5000)");
lua.safe_script("assert(ua:func() == 5000)");
}());
}
@ -481,7 +421,7 @@ TEST_CASE("simple_usertype/class call propogation", "make sure methods and varia
"var", &B::var
);
lua.script(R"(
lua.safe_script(R"(
b = B.new()
print(b.var)
b:thing()
@ -526,10 +466,10 @@ TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-bas
}
);
lua.script("a = f_test()");
lua.script("b = i_test()");
lua.script("c = r_test()");
lua.script("d = f_test.new()");
lua.safe_script("a = f_test()");
lua.safe_script("b = i_test()");
lua.safe_script("c = r_test()");
lua.safe_script("d = f_test.new()");
f_test& a = lua["a"];
f_test& d = lua["d"];
i_test& b = lua["b"];
@ -555,13 +495,13 @@ TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-bas
);
lua.new_simple_usertype<thing>("thing");
lua.script("things = {thing.new(), thing.new()}");
lua.safe_script("things = {thing.new(), thing.new()}");
SECTION("new") {
REQUIRE_NOTHROW(lua.script("a = v_test.new(things)"));
REQUIRE_NOTHROW(lua.safe_script("a = v_test.new(things)"));
}
SECTION("call_constructor") {
REQUIRE_NOTHROW(lua.script("b = v_test(things)"));
REQUIRE_NOTHROW(lua.safe_script("b = v_test(things)"));
}
}
@ -598,7 +538,7 @@ 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.script("print(thing.missingKey)"));
REQUIRE_NOTHROW(lua.safe_script("print(thing.missingKey)"));
}
TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") {
@ -616,7 +556,7 @@ TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runti
"func", &thing::func
);
lua.script(R"(
lua.safe_script(R"(
t = thing.new()
)");
@ -638,19 +578,19 @@ end
REQUIRE_FALSE(result.valid());
}
lua.script("val = t:func(2)");
lua.safe_script("val = t:func(2)");
val = lua["val"];
REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() {
lua.script(R"(
lua.safe_script(R"(
function thing:runtime_func(a)
return a + 1
end
)");
}());
lua.script("val = t:runtime_func(2)");
lua.safe_script("val = t:runtime_func(2)");
val = lua["val"];
REQUIRE(val == 3);
}
@ -663,7 +603,7 @@ end
"v", &thing::v
);
lua.script(R"(
lua.safe_script(R"(
t = thing.new()
)");
@ -685,19 +625,19 @@ end
REQUIRE_FALSE(result.valid());
}());
lua.script("val = t:func(2)");
lua.safe_script("val = t:func(2)");
val = lua["val"];
REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() {
lua.script(R"(
lua.safe_script(R"(
function thing:runtime_func(a)
return a + 1
end
)");
}());
lua.script("val = t:runtime_func(2)");
lua.safe_script("val = t:runtime_func(2)");
val = lua["val"];
REQUIRE(val == 3);
}
@ -715,13 +655,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p
lua.new_simple_usertype<heart_t>("a");
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
lua.safe_script("obj = a.new()");
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.safe_script("v1 = obj:heartbeat()");
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.safe_script("v2 = obj:heartbeat()");
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.safe_script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
@ -739,13 +679,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p
);
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
lua.safe_script("obj = a.new()");
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.safe_script("v1 = obj:heartbeat()");
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.safe_script("v2 = obj:heartbeat()");
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.safe_script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
@ -764,13 +704,13 @@ TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be p
);
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
lua.safe_script("obj = a.new()");
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.safe_script("v1 = obj:heartbeat()");
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.safe_script("v2 = obj:heartbeat()");
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.safe_script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
@ -801,11 +741,11 @@ TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (_
lua["var"] = s;
lua.script("var = sample.new()");
lua.script("var.key = 2");
lua.script("var.__newindex = 4");
lua.script("var.__index = 3");
lua.script("var.__call = 1");
lua.safe_script("var = sample.new()");
lua.safe_script("var.key = 2");
lua.safe_script("var.__newindex = 4");
lua.safe_script("var.__index = 3");
lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3);
@ -831,11 +771,11 @@ TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (_
sol::state lua;
lua.new_simple_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo);
lua.script("var = sample.new()");
lua.script("var.key = 2");
lua.script("var.__newindex = 4");
lua.script("var.__index = 3");
lua.script("var.__call = 1");
lua.safe_script("var = sample.new()");
lua.safe_script("var.key = 2");
lua.safe_script("var.__newindex = 4");
lua.safe_script("var.__index = 3");
lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3);
@ -871,10 +811,10 @@ TEST_CASE("simple_usertype/static properties", "allow for static functions to ge
"g", sol::property(&test_t::s_func, &test_t::g_func)
);
lua.script("v1 = test.f()");
lua.script("v2 = test.g");
lua.script("test.g = 60");
lua.script("v2a = test.g");
lua.safe_script("v1 = test.f()");
lua.safe_script("v2 = test.g");
lua.safe_script("test.g = 60");
lua.safe_script("v2a = test.g");
int v1 = lua["v1"];
REQUIRE(v1 == 24);
double v2 = lua["v2"];
@ -914,7 +854,7 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
sol::meta_function::new_index, &indexing_test::setter
);
lua.script(R"(
lua.safe_script(R"(
local t = test.new()
v = t.a
print(v)
@ -934,7 +874,7 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
lua["test"]["hi"] = [](indexing_test& _self) -> int { return _self.hi(); };
lua.script(R"(
lua.safe_script(R"(
local t = test.new()
v = t.a;
print(v)

View File

@ -164,12 +164,12 @@ TEST_CASE("state/multi require", "make sure that requires transfers across hand-
TEST_CASE("state/require-safety", "make sure unrelated modules aren't harmed in using requires") {
sol::state lua;
lua.open_libraries();
std::string t1 = lua.script(R"(require 'io'
std::string t1 = lua.safe_script(R"(require 'io'
return 'test1')");
sol::object ot2 = lua.require_script("test2", R"(require 'io'
return 'test2')");
std::string t2 = ot2.as<std::string>();
std::string t3 = lua.script(R"(require 'io'
std::string t3 = lua.safe_script(R"(require 'io'
return 'test3')");
REQUIRE(t1 == "test1");
REQUIRE(t2 == "test2");
@ -179,7 +179,7 @@ return 'test3')");
TEST_CASE("state/leak check", "make sure there are no humongous memory leaks in iteration") {
#if 0
sol::state lua;
lua.script(R"(
lua.safe_script(R"(
record = {}
for i=1,256 do
record[i] = i
@ -244,7 +244,7 @@ return example;
auto bar = [&script](sol::this_state l) {
sol::state_view lua = l;
sol::table data = lua.script(script);
sol::table data = lua.safe_script(script);
std::string str = data["str"];
int num = data["num"];
@ -256,7 +256,7 @@ return example;
auto foo = [&script](int, sol::this_state l) {
sol::state_view lua = l;
sol::table data = lua.script(script);
sol::table data = lua.safe_script(script);
std::string str = data["str"];
int num = data["num"];
@ -299,7 +299,7 @@ return example;
lua.set_function("bar", bar);
lua.set_function("bar2", bar2);
lua.script("bar() bar2() foo(1) foo2(1)");
lua.safe_script("bar() bar2() foo(1) foo2(1)");
}
TEST_CASE("state/copy and move", "ensure state can be properly copied and moved") {
@ -318,9 +318,9 @@ TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause
sol::state lua;
sol::stack_guard sg(lua);
lua.open_libraries();
lua.script("require 'io'\nreturn 'test1'");
lua.safe_script("require 'io'\nreturn 'test1'");
lua.require_script("test2", "require 'io'\nreturn 'test2'");
lua.script("require 'io'\nreturn 'test3'");
lua.safe_script("require 'io'\nreturn 'test3'");
}
TEST_CASE("state/script, do, and load", "test success and failure cases for loading and running scripts") {
@ -348,7 +348,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script") {
sol::state lua;
sol::stack_guard sg(lua);
int ar = lua.script(good);
int ar = lua.safe_script(good);
int a = lua["a"];
REQUIRE(a == 21);
REQUIRE(ar == 21);
@ -366,13 +366,13 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script-handler") {
sol::state lua;
sol::stack_guard sg(lua);
auto errbs = lua.script(bad_syntax, sol::script_pass_on_error);
auto errbs = lua.safe_script(bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid());
auto errbr = lua.script(bad_runtime, sol::script_pass_on_error);
auto errbr = lua.safe_script(bad_runtime, sol::script_pass_on_error);
REQUIRE(!errbr.valid());
auto result = lua.script(good, sol::script_pass_on_error);
auto result = lua.safe_script(good, sol::script_pass_on_error);
int a = lua["a"];
int ar = result;
REQUIRE(result.valid());
@ -423,7 +423,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script_file") {
sol::state lua;
sol::stack_guard sg(lua);
int ar = lua.script_file(file_good);
int ar = lua.safe_script_file(file_good);
int a = lua["a"];
REQUIRE(a == 21);
REQUIRE(ar == 21);
@ -441,13 +441,13 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script_file-handler") {
sol::state lua;
sol::stack_guard sg(lua);
auto errbs = lua.script_file(file_bad_syntax, sol::script_pass_on_error);
auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid());
auto errbr = lua.script_file(file_bad_runtime, sol::script_pass_on_error);
auto errbr = lua.safe_script_file(file_bad_runtime, sol::script_pass_on_error);
REQUIRE(!errbr.valid());
auto result = lua.script_file(file_good, sol::script_pass_on_error);
auto result = lua.safe_script_file(file_good, sol::script_pass_on_error);
int a = lua["a"];
int ar = result;
REQUIRE(result.valid());

View File

@ -97,7 +97,7 @@ TEST_CASE("tables/nested cleanup", "make sure tables leave the stack balanced")
sol::state lua;
lua.open_libraries();
lua.script("A={}");
lua.safe_script("A={}");
auto f = [] { return 5; };
for (int i = 0; i < 30; i++) {
std::string name = std::string("init") + std::to_string(i);
@ -143,7 +143,7 @@ TEST_CASE("tables/for_each", "Testing the use of for_each to get values from a l
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("arr = {\n"
lua.safe_script("arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
@ -200,7 +200,7 @@ TEST_CASE("tables/for_each empty", "empty tables should not crash") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("arr = {}");
lua.safe_script("arr = {}");
sol::table tbl = lua["arr"];
REQUIRE(tbl.empty());
std::size_t tablesize = 0;
@ -257,7 +257,7 @@ TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("arr = {\n"
lua.safe_script("arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
@ -316,7 +316,7 @@ 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.script("assert(os.name == \"windows\")"));
REQUIRE_NOTHROW(lua.safe_script("assert(os.name == \"windows\")"));
}
TEST_CASE("tables/create", "Check if creating a table is kosher") {
@ -368,7 +368,7 @@ TEST_CASE("tables/function variables", "Check if tables and function calls work
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os);
auto run_script = [](sol::state& lua) -> void {
lua.script("assert(os.fun() == \"test\")");
lua.safe_script("assert(os.fun() == \"test\")");
};
lua.get<sol::table>("os").set_function("fun",
@ -419,7 +419,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("foo = 20\nbar = \"hello world\"");
lua.safe_script("foo = 20\nbar = \"hello world\"");
// basic retrieval
std::string bar = lua["bar"];
int foo = lua["foo"];
@ -439,7 +439,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
// function setting
lua["test"] = plop_xyz;
REQUIRE_NOTHROW(lua.script("assert(test(10, 11, \"hello\") == 11)"));
REQUIRE_NOTHROW(lua.safe_script("assert(test(10, 11, \"hello\") == 11)"));
// function retrieval
sol::function test = lua["test"];
@ -450,7 +450,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
return x * 2;
};
REQUIRE_NOTHROW(lua.script("assert(lamb(220) == 440)"));
REQUIRE_NOTHROW(lua.safe_script("assert(lamb(220) == 440)"));
// function retrieval of a lambda
sol::function lamb = lua["lamb"];
@ -552,7 +552,7 @@ TEST_CASE("tables/boolean keys", "make sure boolean keys don't get caught up in
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script(R"(
lua.safe_script(R"(
tbl = {}
tbl[true] = 10
tbl[1] = 20

View File

@ -271,7 +271,7 @@ TEST_CASE("usertype/usertype", "Show that we can create classes from usertype an
sol::usertype<fuser> lc{ "add", &fuser::add, "add2", &fuser::add2 };
lua.set_usertype(lc);
lua.script("a = fuser:new()\n"
lua.safe_script("a = fuser:new()\n"
"b = a:add(1)\n"
"c = a:add2(1)\n");
@ -299,7 +299,7 @@ TEST_CASE("usertype/usertype-constructors", "Show that we can create classes fro
sol::usertype<crapola::fuser> lc(con, "add", &crapola::fuser::add, "add2", &crapola::fuser::add2);
lua.set_usertype(lc);
lua.script(
lua.safe_script(
"a = fuser.new(2)\n"
"u = a:add(1)\n"
"v = a:add2(1)\n"
@ -339,7 +339,7 @@ TEST_CASE("usertype/usertype-utility", "Show internal management of classes regi
lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2);
lua.script("a = fuser.new()\n"
lua.safe_script("a = fuser.new()\n"
"b = a:add(1)\n"
"c = a:add2(1)\n");
@ -367,8 +367,8 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
lua.set_usertype(baseusertype);
lua.script("base = Base.new(5)");
REQUIRE_NOTHROW(lua.script("print(base:get_num())"));
lua.safe_script("base = Base.new(5)");
REQUIRE_NOTHROW(lua.safe_script("print(base:get_num())"));
sol::constructors<sol::types<int>> derivedctor;
sol::usertype<Derived> derivedusertype(derivedctor,
@ -378,10 +378,10 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
lua.set_usertype(derivedusertype);
lua.script("derived = Derived.new(7)");
lua.script("dgn = derived:get_num()\n"
lua.safe_script("derived = Derived.new(7)");
lua.safe_script("dgn = derived:get_num()\n"
"print(dgn)");
lua.script("dgn10 = derived:get_num_10()\n"
lua.safe_script("dgn10 = derived:get_num_10()\n"
"print(dgn10)");
REQUIRE((lua.get<int>("dgn10") == 70));
@ -394,7 +394,7 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice
lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f);
lua.script(
lua.safe_script(
"local a = test.new()\n"
"a:g(\"woof\")\n"
"a:f(a)\n"
@ -429,16 +429,16 @@ 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.script("x = test.new()"));
REQUIRE_NOTHROW(lua.script("assert(x:set():get() == 10)"));
REQUIRE_NOTHROW(lua.script("y = x:pointer_get()"));
REQUIRE_NOTHROW(lua.script("y:set():get()"));
REQUIRE_NOTHROW(lua.script("y:fun(10)"));
REQUIRE_NOTHROW(lua.script("x:fun(10)"));
REQUIRE_NOTHROW(lua.script("assert(y:fun(10) == x:fun(10), '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:fun(10) == 100, '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:set():get() == y:set():get(), '...')"));
REQUIRE_NOTHROW(lua.script("assert(y:set():get() == 10, '...')"));
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, '...')"));
}
TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") {
@ -449,9 +449,9 @@ TEST_CASE("usertype/issue-number-thirty-five", "using value types created from l
sol::usertype<Vec> udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length);
lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"print(v:length())"));
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())"));
}
@ -469,11 +469,11 @@ TEST_CASE("usertype/lua-stored-usertype", "ensure usertype values can be stored
// usertype dies, but still usable in lua!
}
REQUIRE_NOTHROW(lua.script("collectgarbage()\n"
REQUIRE_NOTHROW(lua.safe_script("collectgarbage()\n"
"v = Vec.new(1, 2, 3)\n"
"print(v:length())"));
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"print(v:normalized():length())"));
}
@ -489,20 +489,20 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
"length", &Vec::length);
lua.set_usertype(udata);
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
REQUIRE_NOTHROW(lua.safe_script("v = Vec.new(1, 2, 3)\n"
"v2 = Vec.new(0, 1, 0)\n"
"print(v:length())\n"
));
REQUIRE_NOTHROW(lua.script("v.x = 2\n"
REQUIRE_NOTHROW(lua.safe_script("v.x = 2\n"
"v2.y = 2\n"
"print(v.x, v.y, v.z)\n"
"print(v2.x, v2.y, v2.z)\n"
));
REQUIRE_NOTHROW(lua.script("assert(v.x == 2)\n"
REQUIRE_NOTHROW(lua.safe_script("assert(v.x == 2)\n"
"assert(v2.x == 0)\n"
"assert(v2.y == 2)\n"
));
REQUIRE_NOTHROW(lua.script("v.x = 3\n"
REQUIRE_NOTHROW(lua.safe_script("v.x = 3\n"
"local x = v.x\n"
"assert(x == 3)\n"
));
@ -518,8 +518,8 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
);
breaks& b = lua["b"];
REQUIRE_NOTHROW(lua.script("b.f = function () print('BARK!') end"));
REQUIRE_NOTHROW(lua.script("b.f()"));
REQUIRE_NOTHROW(lua.safe_script("b.f = function () print('BARK!') end"));
REQUIRE_NOTHROW(lua.safe_script("b.f()"));
REQUIRE_NOTHROW(b.f());
}
@ -535,8 +535,8 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
}
).get<sol::table>("giver").set_function("stuff", giver::stuff);
REQUIRE_NOTHROW(lua.script("giver.stuff()"));
REQUIRE_NOTHROW(lua.script("t = giver.new()\n"
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"));
@ -575,7 +575,7 @@ TEST_CASE("regressions/one", "issue number 48") {
sol::state lua;
lua.new_usertype<vars>("vars",
"boop", &vars::boop);
REQUIRE_NOTHROW(lua.script("beep = vars.new()\n"
REQUIRE_NOTHROW(lua.safe_script("beep = vars.new()\n"
"beep.boop = 1"));
// test for segfault
auto my_var = lua.get<vars>("beep");
@ -612,37 +612,6 @@ TEST_CASE("usertype/get-set-references", "properly get and set with std::ref sem
REQUIRE(rvar.boop == ref_var.boop);
}
TEST_CASE("usertype/destructor-tests", "Show that proper copies / destruction happens") {
static int created = 0;
static int destroyed = 0;
static void* last_call = nullptr;
struct x {
x() { ++created; }
x(const x&) { ++created; }
x(x&&) { ++created; }
x& operator=(const x&) { return *this; }
x& operator=(x&&) { return *this; }
~x() { ++destroyed; }
};
{
sol::state lua;
lua.new_usertype<x>("x");
x x1;
x x2;
lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1));
x& x1copyref = lua["x1copy"];
x& x2copyref = lua["x2copy"];
x& x1ref = lua["x1ref"];
REQUIRE(created == 4);
REQUIRE(destroyed == 0);
REQUIRE(std::addressof(x1) == std::addressof(x1ref));
REQUIRE(std::addressof(x1copyref) != std::addressof(x1));
REQUIRE(std::addressof(x2copyref) != std::addressof(x2));
}
REQUIRE(created == 4);
REQUIRE(destroyed == 4);
}
TEST_CASE("usertype/private-constructible", "Check to make sure special snowflake types from Enterprise thingamahjongs work properly.") {
int numsaved = factory_test::num_saved;
int numkilled = factory_test::num_killed;
@ -658,9 +627,9 @@ 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.script("assert(f.a == true_a)"));
REQUIRE_NOTHROW(lua.safe_script("assert(f.a == true_a)"));
REQUIRE_NOTHROW(lua.script(
REQUIRE_NOTHROW(lua.safe_script(
"local fresh_f = factory_test:new()\n"
"assert(fresh_f.a == true_a)\n"));
}
@ -682,7 +651,7 @@ TEST_CASE("usertype/const-pointer", "Make sure const pointers can be taken") {
);
lua.set("a", A_x());
lua.set("b", B_foo());
lua.script("x = b:foo(a)");
lua.safe_script("x = b:foo(a)");
int x = lua["x"];
REQUIRE(x == 201);
}
@ -713,7 +682,7 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
const std::string bark_58 = "bark 58";
REQUIRE_NOTHROW(lua.script(
REQUIRE_NOTHROW(lua.safe_script(
"r = woof:new()\n"
"a = r:func(1)\n"
"b = r:func(1, 2)\n"
@ -782,7 +751,7 @@ TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles prop
lua.set("n", nested());
lua.set("o", outer());
lua.set("f", sol::c_call<decltype(&nested::f), &nested::f>);
lua.script(R"(
lua.safe_script(R"(
x = w.b
x.var = 20
val = w.b.var == x.var
@ -839,8 +808,8 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c
sol::meta_function::call_function, &bark::operator()
);
REQUIRE_NOTHROW(lua.script("assert(bark.oh_boy('woo') == 3)"));
REQUIRE_NOTHROW(lua.script("bark.oh_boy()"));
REQUIRE_NOTHROW(lua.safe_script("assert(bark.oh_boy('woo') == 3)"));
REQUIRE_NOTHROW(lua.safe_script("bark.oh_boy()"));
bark b;
lua.set("b", &b);
@ -865,7 +834,7 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c
REQUIRE(z);
REQUIRE(w == 5);
lua.script(R"(
lua.safe_script(R"(
lx = b(1)
ly = getmetatable(b).__call(b, 1)
lz = b.something()
@ -926,11 +895,11 @@ TEST_CASE("usertype/properties", "Check if member properties/variables work") {
bark b;
lua.set("b", &b);
lua.script("b.a = 59");
lua.script("var2_0 = b.a");
lua.script("var2_1 = b.b");
lua.script("b.d = 1568");
lua.script("var2_2 = b.c");
lua.safe_script("b.a = 59");
lua.safe_script("var2_0 = b.a");
lua.safe_script("var2_1 = b.b");
lua.safe_script("b.d = 1568");
lua.safe_script("var2_2 = b.c");
int var2_0 = lua["var2_0"];
int var2_1 = lua["var2_1"];
@ -987,7 +956,7 @@ TEST_CASE("usertype/call_constructor", "make sure lua types can be constructed w
, sol::call_constructor, sol::constructors<sol::types<>, sol::types<int>>()
);
lua.script(R"(
lua.safe_script(R"(
t = thing(256)
)");
@ -1004,13 +973,13 @@ TEST_CASE("usertype/call_constructor-factories", "make sure tables can be passed
sol::call_constructor, sol::factories(&matrix_xf::from_lua_table)
);
lua.script("m = mat{ {1.1, 2.2} }");
lua.safe_script("m = mat{ {1.1, 2.2} }");
lua.new_usertype<matrix_xi>("mati",
sol::call_constructor, sol::factories(&matrix_xi::from_lua_table)
);
lua.script("mi = mati{ {1, 2} }");
lua.safe_script("mi = mati{ {1, 2} }");
matrix_xf& m = lua["m"];
REQUIRE(m.a == 1.1f);
@ -1044,7 +1013,7 @@ TEST_CASE("usertype/call_constructor_2", "prevent metatable regression") {
sol::call_constructor, sol::constructors<sol::types<>, sol::types<const class02&>, sol::types<const class01&>>()
);
REQUIRE_NOTHROW(lua.script(R"(
REQUIRE_NOTHROW(lua.safe_script(R"(
x = class01()
y = class02(x)
)"));
@ -1138,7 +1107,7 @@ TEST_CASE("usertype/coverage", "try all the things") {
INFO("usertype created");
lua.script(R"(
lua.safe_script(R"(
e = ext_getset()
w = e:x(e:x(), e:x(e:x()))
print(w)
@ -1149,7 +1118,7 @@ print(w)
INFO("REQUIRE(w) successful");
lua.script(R"(
lua.safe_script(R"(
e:set(500)
e.sset(24)
x = e:get()
@ -1163,7 +1132,7 @@ y = e.sget(20)
INFO("REQUIRE(x, y) successful");
lua.script(R"(
lua.safe_script(R"(
e.bark = 5001
a = e:get()
print(e.bark)
@ -1182,7 +1151,7 @@ print(b)
INFO("REQUIRE(a, b) successful");
lua.script(R"(
lua.safe_script(R"(
c = e.readonlybark
d = e.meow
print(e.readonlybark)
@ -1198,7 +1167,7 @@ print(d)
INFO("REQUIRE(c, d) successful");
lua.script(R"(
lua.safe_script(R"(
e.writeonlypropbark = 500
z = e.readonlypropbark
print(e.readonlybark)
@ -1239,7 +1208,7 @@ TEST_CASE("usertype/copyability", "make sure user can write to a class variable
lua.new_usertype<NoCopy>("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set));
REQUIRE_NOTHROW(
lua.script(R"__(
lua.safe_script(R"__(
nocopy = NoCopy.new()
nocopy.val = 5
)__")
@ -1260,7 +1229,7 @@ TEST_CASE("usertype/protect", "users should be allowed to manually protect a fun
);
REQUIRE_NOTHROW(
lua.script(R"__(
lua.safe_script(R"__(
pm = protect_me.new()
value = pcall(pm.gen,pm)
)__")
@ -1269,59 +1238,6 @@ value = pcall(pm.gen,pm)
REQUIRE_FALSE(value);
}
TEST_CASE("usertype/shared-ptr-regression", "usertype metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
test() {
++created;
}
~test() {
++destroyed;
}
};
{
std::list<std::shared_ptr<test>> tests;
sol::state lua;
lua.open_libraries();
lua.new_usertype<test>("test",
"create", [&]() -> std::shared_ptr<test> {
tests.push_back(std::make_shared<test>());
return tests.back();
}
);
REQUIRE(created == 0);
REQUIRE(destroyed == 0);
lua.script("x = test.create()");
REQUIRE(created == 1);
REQUIRE(destroyed == 0);
REQUIRE_FALSE(tests.empty());
std::shared_ptr<test>& x = lua["x"];
std::size_t xuse = x.use_count();
std::size_t tuse = tests.back().use_count();
REQUIRE(xuse == tuse);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 1);
}
TEST_CASE("usertype/double-deleter-guards", "usertype metatables internally must not rely on C++ state") {
struct c_a { int x; };
struct c_b { int y; };
auto routine = []() {
sol::state lua;
lua.new_usertype<c_a>("c_a", "x", &c_a::x);
lua.new_usertype<c_b>("c_b", "y", &c_b::y);
lua = sol::state();
lua.new_usertype<c_a>("c_a", "x", &c_a::x);
lua.new_usertype<c_b>("c_b", "y", &c_b::y);
lua = sol::state();
};
REQUIRE_NOTHROW(routine());
}
TEST_CASE("usertype/vars", "usertype vars can bind various class items") {
static int muh_variable = 25;
static int through_variable = 10;
@ -1349,7 +1265,7 @@ TEST_CASE("usertype/vars", "usertype vars can bind various class items") {
REQUIRE(pretg2 == 10);
REQUIRE(pretrg2 == 10);
lua.script(R"(
lua.safe_script(R"(
print(test.straight)
test.straight = 50
print(test.straight)
@ -1357,7 +1273,7 @@ print(test.straight)
int s = lua["test"]["straight"];
REQUIRE(s == 50);
lua.script(R"(
lua.safe_script(R"(
t = test.new()
print(t.global)
t.global = 50
@ -1368,7 +1284,7 @@ print(t.global)
REQUIRE(muh_variable == 25);
lua.script(R"(
lua.safe_script(R"(
print(t.ref_global)
t.ref_global = 50
print(t.ref_global)
@ -1378,7 +1294,7 @@ print(t.ref_global)
REQUIRE(muh_variable == 50);
REQUIRE(through_variable == 10);
lua.script(R"(
lua.safe_script(R"(
print(test.global2)
test.global2 = 35
print(test.global2)
@ -1387,7 +1303,7 @@ print(test.global2)
REQUIRE(through_variable == 10);
REQUIRE(tv == 35);
lua.script(R"(
lua.safe_script(R"(
print(test.ref_global2)
test.ref_global2 = 35
print(test.ref_global2)
@ -1421,10 +1337,10 @@ TEST_CASE("usertype/static-properties", "allow for static functions to get and s
"g", sol::property(&test_t::s_func, &test_t::g_func)
);
lua.script("v1 = test.f()");
lua.script("v2 = test.g");
lua.script("test.g = 60");
lua.script("v2a = test.g");
lua.safe_script("v1 = test.f()");
lua.safe_script("v2 = test.g");
lua.safe_script("test.g = 60");
lua.safe_script("v2a = test.g");
int v1 = lua["v1"];
REQUIRE(v1 == 24);
double v2 = lua["v2"];
@ -1455,7 +1371,7 @@ TEST_CASE("usertype/var-and-property", "make sure const vars are readonly and pr
"global", sol::var(std::ref(arf))
);
lua.script(R"(
lua.safe_script(R"(
t = test.new()
print(t.prop)
t.prop = 50
@ -1465,7 +1381,7 @@ print(t.prop)
test& t = lua["t"];
REQUIRE(t.value == 50);
lua.script(R"(
lua.safe_script(R"(
t = test.new()
print(t.global)
)");
@ -1473,7 +1389,7 @@ print(t.global)
auto result = lua.safe_script("t.global = 20", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
lua.script("print(t.global)");
lua.safe_script("print(t.global)");
}
TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't get pushed as references with function calls and the like") {
@ -1492,7 +1408,7 @@ TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't ge
"get_name", &Entity::GetName
);
lua.script(R"(
lua.safe_script(R"(
function my_func(entity)
print("INSIDE LUA")
print(entity:get_name())
@ -1514,7 +1430,7 @@ TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and
lua.new_usertype<abstract_A>("A", "a", &abstract_A::a);
lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>());
REQUIRE_NOTHROW([&]() {
lua.script(R"(
lua.safe_script(R"(
local b = B.new()
b:a()
)");
@ -1533,45 +1449,14 @@ TEST_CASE("usertype/as_function", "Ensure that variables can be turned into func
B b;
lua.set("b", &b);
lua.script("x = b:f()");
lua.script("y = b.b");
lua.safe_script("x = b:f()");
lua.safe_script("y = b.b");
int x = lua["x"];
int y = lua["y"];
REQUIRE(x == 24);
REQUIRE(y == 24);
}
TEST_CASE("usertype/destruction-test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
sol::state lua;
class CrashClass {
public:
CrashClass() {
}
~CrashClass() {
a = 10; // This will cause a crash.
}
private:
int a;
};
lua.new_usertype<CrashClass>("CrashClass",
sol::call_constructor, sol::constructors<sol::types<>>()
);
lua.script(R"(
function testCrash()
local x = CrashClass()
end
)");
for (int i = 0; i < 1000; ++i) {
lua["testCrash"]();
}
}
TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializers work well") {
struct A {
double f = 25.5;
@ -1588,7 +1473,7 @@ TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializ
sol::call_constructor, sol::initializers(&A::init)
);
lua.script(R"(
lua.safe_script(R"(
a = A(24.3)
)");
A& a = lua["a"];
@ -1602,7 +1487,7 @@ 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.script("v = thing.missingKey\nprint(v)"));
REQUIRE_NOTHROW(lua.safe_script("v = thing.missingKey\nprint(v)"));
sol::object o = lua["v"];
bool isnil = o.is<sol::lua_nil_t>();
REQUIRE(isnil);
@ -1623,7 +1508,7 @@ TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime exte
"func", &thing::func
);
lua.script(R"(
lua.safe_script(R"(
t = thing.new()
)");
@ -1645,19 +1530,19 @@ end
REQUIRE_FALSE(result.valid());
};
lua.script("val = t:func(2)");
lua.safe_script("val = t:func(2)");
val = lua["val"];
REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() {
lua.script(R"(
lua.safe_script(R"(
function thing:runtime_func(a)
return a + 1
end
)");
}());
lua.script("val = t:runtime_func(2)");
lua.safe_script("val = t:runtime_func(2)");
val = lua["val"];
REQUIRE(val == 3);
}
@ -1670,7 +1555,7 @@ end
"v", &thing::v
);
lua.script(R"(
lua.safe_script(R"(
t = thing.new()
)");
@ -1692,19 +1577,19 @@ end
REQUIRE_FALSE(result.valid());
};
lua.script("val = t:func(2)");
lua.safe_script("val = t:func(2)");
val = lua["val"];
REQUIRE(val == 2);
REQUIRE_NOTHROW([&lua]() {
lua.script(R"(
lua.safe_script(R"(
function thing:runtime_func(a)
return a + 1
end
)");
}());
lua.script("val = t:runtime_func(2)");
lua.safe_script("val = t:runtime_func(2)");
val = lua["val"];
REQUIRE(val == 3);
}
@ -1722,13 +1607,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly
lua.new_usertype<heart_t>("a");
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
lua.safe_script("obj = a.new()");
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.safe_script("v1 = obj:heartbeat()");
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.safe_script("v2 = obj:heartbeat()");
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.safe_script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
@ -1746,13 +1631,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly
);
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
lua.safe_script("obj = a.new()");
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.safe_script("v1 = obj:heartbeat()");
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.safe_script("v2 = obj:heartbeat()");
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.safe_script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
@ -1771,13 +1656,13 @@ TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly
);
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
lua.safe_script("obj = a.new()");
lua.safe_script("function a:heartbeat () print('arf') return 1 end");
lua.safe_script("v1 = obj:heartbeat()");
lua.safe_script("function a:heartbeat () print('bark') return 2 end");
lua.safe_script("v2 = obj:heartbeat()");
lua.safe_script("a.heartbeat = function(self) print('woof') return 3 end");
lua.safe_script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
@ -1808,11 +1693,11 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index,
lua["var"] = s;
lua.script("var = sample.new()");
lua.script("var.key = 2");
lua.script("var.__newindex = 4");
lua.script("var.__index = 3");
lua.script("var.__call = 1");
lua.safe_script("var = sample.new()");
lua.safe_script("var.key = 2");
lua.safe_script("var.__newindex = 4");
lua.safe_script("var.__index = 3");
lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3);
@ -1838,11 +1723,11 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index,
sol::state lua;
lua.new_usertype<sample>("sample", sol::meta_function::new_index, &sample::foo);
lua.script("var = sample.new()");
lua.script("var.key = 2");
lua.script("var.__newindex = 4");
lua.script("var.__index = 3");
lua.script("var.__call = 1");
lua.safe_script("var = sample.new()");
lua.safe_script("var.key = 2");
lua.safe_script("var.__newindex = 4");
lua.safe_script("var.__index = 3");
lua.safe_script("var.__call = 1");
REQUIRE(values[0] == 2);
REQUIRE(values[1] == 4);
REQUIRE(values[2] == 3);
@ -1871,9 +1756,9 @@ TEST_CASE("usertype/noexcept-methods", "make sure noexcept functinos and methods
"nm", &T::noexcept_method
);
lua.script("t = T.new()");
lua.script("v1 = t.nf()");
lua.script("v2 = t:nm()");
lua.safe_script("t = T.new()");
lua.safe_script("v1 = t.nf()");
lua.safe_script("v2 = t:nm()");
int v1 = lua["v1"];
int v2 = lua["v2"];
REQUIRE(v1 == 0x61);

View File

@ -52,8 +52,8 @@ TEST_CASE("utility/variant", "test that variant can be round-tripped") {
});
lua["v"] = std::variant<float, int, std::string>(2);
REQUIRE_NOTHROW([&]() {
lua.script("assert(f(v))");
lua.script("assert(g(v))");
lua.safe_script("assert(f(v))");
lua.safe_script("assert(g(v))");
}());
}
SECTION("throws") {
@ -93,7 +93,7 @@ TEST_CASE("utility/string_view", "test that string_view can be taken as an argum
lua["v"] = "bark!";
REQUIRE_NOTHROW([&]() {
lua.script("assert(f(v))");
lua.safe_script("assert(f(v))");
}());
#else
REQUIRE(true);
@ -148,9 +148,9 @@ TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhe
int a = fx(25, 25);
INFO("finished setting fx");
INFO("calling a script");
lua.script("a = with_state_2(25, 25)");
lua.safe_script("a = with_state_2(25, 25)");
INFO("calling c script");
lua.script("c = b:with_state(25, 25)");
lua.safe_script("c = b:with_state(25, 25)");
INFO("getting a");
int la = lua["a"];
INFO("getting b");

View File

@ -25,9 +25,9 @@ TEST_CASE("variadics/variadic_args", "Check to see we can receive multiple argum
return{ r, r > 200 };
});
lua.script("x = v(25, 25)");
lua.script("x2 = v(25, 25, 100, 50, 250, 150)");
lua.script("x3 = v(1, 2, 3, 4, 5, 6)");
lua.safe_script("x = v(25, 25)");
lua.safe_script("x2 = v(25, 25, 100, 50, 250, 150)");
lua.safe_script("x3 = v(1, 2, 3, 4, 5, 6)");
structure& lx = lua["x"];
structure& lx2 = lua["x2"];
@ -46,8 +46,8 @@ TEST_CASE("variadics/required with variadic_args", "Check if a certain number of
[](sol::this_state, sol::variadic_args, int, int) {
}
);
REQUIRE_NOTHROW(lua.script("v(20, 25, 30)"));
REQUIRE_NOTHROW(lua.script("v(20, 25)"));
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());
}
@ -72,8 +72,8 @@ TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types pr
REQUIRE(working);
});
lua.script("f(1, 'bark', true)");
lua.script("f(2, 'wuf', false)");
lua.safe_script("f(1, 'bark', true)");
lua.safe_script("f(2, 'wuf', false)");
}
TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") {
@ -90,7 +90,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
});
REQUIRE_NOTHROW([&]() {
lua.script(R"(
lua.safe_script(R"(
v1, v2, v3 = f()
v4, v5 = g()
)");
@ -116,7 +116,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
});
REQUIRE_NOTHROW([&]() {
lua.script(R"(
lua.safe_script(R"(
v1, v2, v3 = f(1, 'bark', true)
v4, v5 = f(25, 82)
)");
@ -156,7 +156,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
});
REQUIRE_NOTHROW([&]() {
lua.script(R"(
lua.safe_script(R"(
v1, v2, v3 = f(true)
v4, v5, v6, v7 = f(false)
)");
@ -208,10 +208,10 @@ TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves
);
REQUIRE_NOTHROW([&]() {
lua.script("v0 = vec2();");
lua.script("v1 = vec2(1);");
lua.script("v2 = vec2(1, 2);");
lua.script("v3 = vec2(v2)");
lua.safe_script("v0 = vec2();");
lua.safe_script("v1 = vec2(1);");
lua.safe_script("v2 = vec2(1, 2);");
lua.safe_script("v3 = vec2(v2)");
}());
vec2& v0 = lua["v0"];

View File

@ -77,40 +77,40 @@ TEST_CASE("simple/set", "Check if the set works properly.") {
test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("a", 9);
} REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.script("if a ~= 9 then error('wrong value') end"));
REQUIRE_NOTHROW(lua.safe_script("if a ~= 9 then error('wrong value') end"));
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("d", "hello");
} REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
REQUIRE_NOTHROW(lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("e", std::string("hello"), "f", true);
} REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
REQUIRE_NOTHROW(lua.script("if f ~= true then error('wrong value') end"));
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"));
}
TEST_CASE("simple/get", "Tests if the get function works properly.") {
sol::state lua;
int begintop = 0, endtop = 0;
lua.script("a = 9");
lua.safe_script("a = 9");
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
auto a = lua.get<int>("a");
REQUIRE(a == 9.0);
} REQUIRE(begintop == endtop);
lua.script("b = nil");
lua.safe_script("b = nil");
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
REQUIRE_NOTHROW(lua.get<sol::nil_t>("b"));
} REQUIRE(begintop == endtop);
lua.script("d = 'hello'");
lua.script("e = true");
lua.safe_script("d = 'hello'");
lua.safe_script("e = true");
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
std::string d;
@ -124,7 +124,7 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") {
TEST_CASE("simple/set and get global integer", "Tests if the get function works properly with global integers") {
sol::state lua;
lua[1] = 25.4;
lua.script("b = 1");
lua.safe_script("b = 1");
double a = lua.get<double>(1);
double b = lua.get<double>("b");
REQUIRE(a == 25.4);
@ -169,7 +169,7 @@ TEST_CASE("simple/addition", "check if addition works and can be gotten through
sol::state lua;
lua.set("b", 0.2);
lua.script("c = 9 + b");
lua.safe_script("c = 9 + b");
auto c = lua.get<double>("c");
REQUIRE(c == 9.2);
@ -179,7 +179,7 @@ TEST_CASE("simple/if", "check if if statements work through lua") {
sol::state lua;
std::string program = "if true then f = 0.1 else f = 'test' end";
lua.script(program);
lua.safe_script(program);
auto f = lua.get<double>("f");
REQUIRE(f == 0.1);
@ -223,7 +223,7 @@ TEST_CASE("interop/null-to-nil-and-back", "nil should be the given type when a p
lua.set_function("rofl", [](int* x) {
INFO(x);
});
REQUIRE_NOTHROW(lua.script("x = lol()\n"
REQUIRE_NOTHROW(lua.safe_script("x = lol()\n"
"rofl(x)\n"
"assert(x == nil)"));
}
@ -234,7 +234,7 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made
struct d {};
lua.script("function f () print('bark') end");
lua.safe_script("function f () print('bark') end");
lua["d"] = d{};
lua["l"] = static_cast<void*>(nullptr);
@ -317,7 +317,7 @@ TEST_CASE("feature/indexing overrides", "make sure index functions can be overri
, "props", sol::property(&DynamicObject::get_dynamic_props)
);
lua.script(R"__(
lua.safe_script(R"__(
obj = DynamicObject:new()
obj.props.name = 'test name'
print('name = ' .. obj.props.name)
@ -356,7 +356,7 @@ TEST_CASE("features/indexing numbers", "make sure indexing functions can be over
lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(),
sol::meta_function::index, &vector::my_index,
sol::meta_function::new_index, &vector::my_new_index);
lua.script("v = vector.new()\n"
lua.safe_script("v = vector.new()\n"
"print(v[1])\n"
"v[2] = 3\n"
"print(v[2])\n"
@ -403,7 +403,7 @@ TEST_CASE("features/multiple inheritance", "Ensure that multiple inheritance wor
"a2", &complex::a2,
sol::base_classes, sol::bases<base1, base2>()
);
lua.script("c = complex.new()\n"
lua.safe_script("c = complex.new()\n"
"s = simple.new()\n"
"b1 = base1.new()\n"
"b2 = base1.new()\n"
@ -455,7 +455,7 @@ TEST_CASE("optional/left out args", "Make sure arguments can be left out of opti
// sol::optional needs an argument no matter what?
lua.set_function("func_opt_ret_bool", func_opt_ret_bool);
REQUIRE_NOTHROW([&]{
lua.script(R"(
lua.safe_script(R"(
func_opt_ret_bool(42)
func_opt_ret_bool()
print('ok')
@ -496,7 +496,7 @@ TEST_CASE("proxy/proper-pushing", "allow proxies to reference other proxies and
T t;
lua["t1"] = &t;
lua["t2"] = lua["t1"];
lua.script("b = t1 == t2");
lua.safe_script("b = t1 == t2");
bool b = lua["b"];
REQUIRE(b);
}
@ -563,7 +563,7 @@ 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.script("assert(is_thing(a))"));
REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))"));
}
SECTION("object")
@ -572,6 +572,6 @@ 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.script("assert(is_thing(a))"));
REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))"));
}
}