This mega-commit produces simple_usertype to allow for faster compile times by avoiding the use of __index internally. It sacrifices some speed and some storage optimizations and also does not allow variable syntax, but the produced table is directly modifiable.

Adds a `protect()` function to trigger safety for an item.
This commit also optimizes away all instances of virtual function calls for function calls and storage. Will need to test speed to see how it works out.
Closes #133
Closes #134
Closes #135
Closes #136
This commit is contained in:
ThePhD 2016-07-07 16:52:39 -04:00
parent 76b73bdfab
commit 27174aba9c
23 changed files with 735 additions and 391 deletions

1
.gitignore vendored
View File

@ -62,3 +62,4 @@ single/sol.hpp
lua53.dll
main.exe
main.o
lua-5.3.3/

View File

@ -22,6 +22,7 @@
#ifndef SOL_CALL_HPP
#define SOL_CALL_HPP
#include "protect.hpp"
#include "wrapper.hpp"
#include "property.hpp"
#include "stack.hpp"
@ -90,7 +91,7 @@ namespace sol {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (traits::free_arity != fxarity) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
@ -111,7 +112,7 @@ namespace sol {
}
template <typename T, typename... TypeLists, typename Match, typename... Args>
inline int construct(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
// use same overload resolution matching as all other parts of the framework
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
@ -130,7 +131,7 @@ namespace sol {
reference userdataref(L, -1);
userdataref.pop();
construct<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
construct_match<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &meta[0]);
@ -143,14 +144,14 @@ namespace sol {
return 1;
}
template <typename F, bool is_index, bool is_variable, typename = void>
template <typename F, bool is_index, bool is_variable, bool checked, typename = void>
struct agnostic_lua_call_wrapper {
static int var_call(std::true_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
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<is_index ? 1 : 2>(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f);
return stack::call_into_lua<is_index ? 1 : 2, checked>(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f);
}
static int var_call(std::false_type, lua_State* L, F& f) {
@ -158,7 +159,7 @@ namespace sol {
typedef typename wrap::free_args_list args_list;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f);
return stack::call_into_lua<0, checked>(returns_list(), args_list(), L, 1, caller(), f);
}
static int call(lua_State* L, F& f) {
@ -166,78 +167,80 @@ namespace sol {
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, C> {
template <bool is_index, bool is_variable, bool checked, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, C> {
static int call(lua_State* L, lua_r_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, C> {
template <bool is_index, bool is_variable, bool checked, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, C> {
static int call(lua_State* L, lua_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
template <bool is_index, bool is_variable, bool checked, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, 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, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, C> {
template <bool is_index, bool is_variable, bool checked, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, C> {
static int call(lua_State* L, const no_construction&) {
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
}
};
template <typename... Args, bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, C> {
template <typename... Args, bool is_index, bool is_variable, bool checked, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, C> {
static int call(lua_State*, const bases<Args...>&) {
// Uh. How did you even call this, lul
return 0;
}
};
template <typename T, typename F, bool is_index, bool is_variable, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable> {};
template <typename T, typename F, bool is_index, bool is_variable, bool checked = stack::stack_detail::default_check_arguments, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked> {};
template <typename T, typename F, bool is_index, bool is_variable>
struct lua_call_wrapper<T, F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
template <typename T, typename F, bool is_index, bool is_variable, bool checked>
struct lua_call_wrapper<T, F, is_index, is_variable, checked, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list;
typedef typename wrap::caller caller;
typedef typename wrap::object_type object_type;
typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta;
#ifdef SOL_SAFE_USERTYPE
object_type* o = static_cast<object_type*>(stack::get<T*>(L, 1));
object_type* o = static_cast<object_type*>(stack::get<Ta*>(L, 1));
if (o == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
return stack::call_into_lua<is_variable ? 2 : 1, checked>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = static_cast<object_type&>(stack::get<T&>(L, 1));
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
object_type& o = static_cast<object_type&>(stack::get<Ta&>(L, 1));
return stack::call_into_lua<is_variable ? 2 : 1, checked>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
};
template <typename T, typename F, bool is_variable>
struct lua_call_wrapper<T, F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
template <typename T, typename F, bool is_variable, bool checked>
struct lua_call_wrapper<T, F, false, is_variable, checked, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call_assign(std::true_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::args_list args_list;
typedef typename wrap::object_type object_type;
typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta;
typedef typename wrap::caller caller;
#ifdef SOL_SAFE_USERTYPE
object_type* o = static_cast<object_type*>(stack::get<T*>(L, 1));
object_type* o = static_cast<object_type*>(stack::get<Ta*>(L, 1));
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
@ -246,7 +249,7 @@ namespace sol {
}
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = static_cast<object_type&>(stack::get<T&>(L, 1));
object_type& o = static_cast<object_type&>(stack::get<Ta&>(L, 1));
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
@ -269,8 +272,8 @@ namespace sol {
}
};
template <typename T, typename F, bool is_variable>
struct lua_call_wrapper<T, F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
template <typename T, typename F, bool is_variable, bool checked>
struct lua_call_wrapper<T, F, true, is_variable, checked, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call(lua_State* L, F& f) {
@ -286,16 +289,16 @@ namespace sol {
}
return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o);
return stack::call_into_lua<is_variable ? 2 : 1, checked>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = static_cast<object_type&>(stack::get<T&>(L, 1));
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o);
return stack::call_into_lua<is_variable ? 2 : 1, checked>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
};
template <typename T, typename... Args, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, C> {
template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, typename C>
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, checked, C> {
typedef sol::constructor_list<Args...> F;
static int call(lua_State* L, F&) {
@ -310,7 +313,7 @@ namespace sol {
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj;
construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
construct_match<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &metakey[0]);
@ -324,8 +327,8 @@ namespace sol {
}
};
template <typename T, typename... Cxs, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> {
template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, typename C>
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, checked, C> {
typedef sol::constructor_wrapper<Cxs...> F;
struct onmatch {
@ -339,7 +342,7 @@ namespace sol {
referencepointer = obj;
auto& func = std::get<I>(f.set);
stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
stack::call_into_lua<1, checked>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
userdataref.push();
luaL_getmetatable(L, &metakey[0]);
@ -359,13 +362,13 @@ namespace sol {
call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable);
int syntaxval = static_cast<int>(syntax);
int argcount = lua_gettop(L) - syntaxval;
return construct<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
}
};
template <typename T, typename Fx, bool is_index, bool is_variable>
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<std::is_void<Fx>::value>> {
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked>
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, checked, std::enable_if_t<std::is_void<Fx>::value>> {
typedef sol::destructor_wrapper<Fx> F;
static int call(lua_State* L, const F&) {
@ -373,8 +376,8 @@ namespace sol {
}
};
template <typename T, typename Fx, bool is_index, bool is_variable>
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<!std::is_void<Fx>::value>> {
template <typename T, typename Fx, bool is_index, bool is_variable, bool checked>
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, checked, std::enable_if_t<!std::is_void<Fx>::value>> {
typedef sol::destructor_wrapper<Fx> F;
static int call(lua_State* L, const F& f) {
@ -384,15 +387,15 @@ namespace sol {
}
};
template <typename T, typename... Fs, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, C> {
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, typename C>
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, C> {
typedef overload_set<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.set);
return lua_call_wrapper<T, Fx, is_index, is_variable>{}.call(L, f);
return lua_call_wrapper<T, Fx, is_index, is_variable, checked>{}.call(L, f);
}
};
@ -401,11 +404,26 @@ namespace sol {
}
};
template <typename T, typename V, bool is_index, bool is_variable, bool checked, typename C>
struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, C> {
typedef protect_t<V> F;
static int call(lua_State* L, F& fx) {
return lua_call_wrapper<T, V, is_index, is_variable, true>{}.call(L, fx.value);
}
};
template <typename T, bool is_index, bool is_variable, typename Fx>
int call_wrapped(lua_State* L, Fx&& fx) {
inline int call_wrapped(lua_State* L, Fx&& fx) {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable>{}.call(L, std::forward<Fx>(fx));
}
template <typename T, bool is_index, bool is_variable, typename F>
inline int call_user(lua_State* L) {
auto& fx = stack::get<user<F>>(L, upvalue_index(1));
return call_wrapped<T, is_index, is_variable>(L, fx);
}
template <typename T, typename = void>
struct is_var_bind : std::false_type {};
@ -428,4 +446,4 @@ namespace sol {
} // sol
#endif // SOL_CALL_HPP
#endif // SOL_CALL_HPP

View File

@ -24,8 +24,8 @@
#include "function_types_core.hpp"
#include "function_types_templated.hpp"
#include "function_types_basic.hpp"
#include "function_types_member.hpp"
#include "function_types_stateless.hpp"
#include "function_types_stateful.hpp"
#include "function_types_overloaded.hpp"
#include "resolve.hpp"
#include "call.hpp"
@ -44,13 +44,51 @@ namespace sol {
}
namespace stack {
template <typename F, typename G>
struct pusher<property_wrapper<F, G>, std::enable_if_t<!std::is_void<F>::value && !std::is_void<G>::value>> {
static int push(lua_State* L, property_wrapper<F, G> pw) {
return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write)));
}
};
template <typename F>
struct pusher<property_wrapper<F, void>> {
static int push(lua_State* L, property_wrapper<F, void> pw) {
return stack::push(L, std::move(pw.read));
}
};
template <typename F>
struct pusher<property_wrapper<void, F>> {
static int push(lua_State* L, property_wrapper<void, F> pw) {
return stack::push(L, std::move(pw.write));
}
};
template <typename T, typename... Lists>
struct pusher<detail::constructors_for<T, constructor_list<Lists...>>> {
static int push(lua_State* L, detail::constructors_for<T, constructor_list<Lists...>>) {
lua_CFunction cf = call_detail::construct<T, Lists...>;
return stack::push(L, cf);
}
};
template <typename T, typename... Fxs>
struct pusher<detail::constructors_for<T, constructor_wrapper<Fxs...>>> {
static int push(lua_State* L, constructor_wrapper<Fxs...> c) {
lua_CFunction cf = call_detail::call_user<T, false, false>;
int closures = stack::push(L, make_user(std::move(c)));
return stack::push(L, c_closure(cf, 1));
}
};
template<typename... Sigs>
struct pusher<function_sig<Sigs...>> {
template <typename... Sig, typename Fx, typename... Args>
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<clean_fx>>(std::forward<Fx>(fx), std::forward<Args>(args)...);
set_fx(L, std::move(sptr));
typedef function_detail::functor_function<clean_fx> F;
set_fx<F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <typename R, typename... A, typename Fx, typename... Args>
@ -62,7 +100,7 @@ namespace sol {
template <typename R, typename... A, typename Fx, typename... Args>
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::decay_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> raw_fx_t;
typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t;
typedef R(*fx_ptr_t)(A...);
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
@ -70,15 +108,15 @@ namespace sol {
template <typename Fx, typename... Args>
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
typedef meta::function_signature_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> Sig;
typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_variable<meta::unqualified_t<T>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
set_fx(L, std::move(sptr));
typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx> F;
set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <typename Fx, typename T, typename... Args>
@ -114,9 +152,9 @@ namespace sol {
template <typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<meta::unwrapped_t<meta::unqualified_t<T>>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
set_fx(L, std::move(sptr));
typedef std::decay_t<Fx> clean_fx;
typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx> F;
set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <typename Fx, typename T, typename... Args>
@ -173,14 +211,11 @@ namespace sol {
select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
function_detail::base_function* target = luafunc.release();
void* targetdata = static_cast<void*>(target);
lua_CFunction freefunc = function_detail::call;
template <typename Fx, typename... Args>
static void set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>>;
stack::push(L, userdata_value(targetdata));
function_detail::free_function_cleanup(L);
lua_setmetatable(L, -2);
stack::push<user<Fx>>(L, std::forward<Args>(args)...);
stack::push(L, c_closure(freefunc, 1));
}
@ -231,12 +266,14 @@ namespace sol {
template<typename... Functions>
struct pusher<overload_set<Functions...>> {
static int push(lua_State* L, overload_set<Functions...>&& set) {
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set)));
typedef function_detail::overloaded_function<Functions...> F;
pusher<function_sig<>>{}.set_fx<F>(L, std::move(set.set));
return 1;
}
static int push(lua_State* L, const overload_set<Functions...>& set) {
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set));
typedef function_detail::overloaded_function<Functions...> F;
pusher<function_sig<>>{}.set_fx<F>(L, set.set);
return 1;
}
};

View File

@ -33,83 +33,10 @@ namespace sol {
return name;
}
struct base_function {
virtual int operator()(lua_State* L) {
return luaL_error(L, "sol: failure to call specialized wrapped C++ function from Lua");
}
virtual ~base_function() {}
};
static int base_call(lua_State* L, void* inheritancedata) {
if (inheritancedata == nullptr) {
return luaL_error(L, "sol: call from Lua to C++ function has null data");
}
base_function* pfx = static_cast<base_function*>(inheritancedata);
base_function& fx = *pfx;
return detail::trampoline(L, fx);
}
static int base_gc(lua_State* L, void* udata) {
if (udata == nullptr) {
return luaL_error(L, "sol: call from lua to C++ gc function with null data");
}
base_function* ptr = static_cast<base_function*>(udata);
std::default_delete<base_function> dx{};
dx(ptr);
return 0;
}
template <std::size_t limit>
static void func_gc(std::true_type, lua_State*) {
}
template <std::size_t limit>
static void func_gc(std::false_type, lua_State* L) {
for (std::size_t i = 0; i < limit; ++i) {
void* value = stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(i + 1)));
if (value == nullptr)
continue;
base_function* obj = static_cast<base_function*>(value);
std::allocator<base_function> alloc{};
alloc.destroy(obj);
alloc.deallocate(obj, 1);
}
}
template <typename Fx>
inline int call(lua_State* L) {
void* ludata = stack::get<lightuserdata_value>(L, up_value_index(1));
void** pinheritancedata = static_cast<void**>(ludata);
return base_call(L, *pinheritancedata);
}
inline int gc(lua_State* L) {
void* udata = stack::get<userdata_value>(L, 1);
void** pudata = static_cast<void**>(udata);
return base_gc(L, *pudata);
}
template<std::size_t I>
inline int usertype_call(lua_State* L) {
// Zero-based template parameter, but upvalues start at 1
return base_call(L, stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(I + 1))));
}
template<std::size_t I>
inline int usertype_gc(lua_State* L) {
func_gc<I>(meta::boolean<(I < 1)>(), L);
return 0;
}
inline void free_function_cleanup(lua_State* L) {
const static char* metatablename = &cleanup_key()[0];
int metapushed = luaL_newmetatable(L, metatablename);
if (metapushed == 1) {
stack::set_field(L, "__gc", function_detail::gc);
}
Fx& fx = stack::get<user<Fx>>(L, upvalue_index(1));
return fx(L);
}
} // function_detail
} // sol

View File

@ -1,155 +0,0 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FUNCTION_TYPES_MEMBER_HPP
#define SOL_FUNCTION_TYPES_MEMBER_HPP
#include "function_types_core.hpp"
namespace sol {
namespace function_detail {
template<typename Func>
struct free_function : public base_function {
typedef meta::unwrapped_t<meta::unqualified_t<Func>> Function;
typedef meta::function_return_t<Function> return_type;
typedef meta::function_args_t<Function> args_lists;
Function fx;
template<typename... Args>
free_function(Args&&... args): fx(std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
auto f = [&](lua_State* L) -> int { return this->call(L);};
return detail::trampoline(L, f);
}
};
template<typename Func>
struct functor_function : public base_function {
typedef meta::unwrapped_t<meta::unqualified_t<Func>> Function;
typedef decltype(&Function::operator()) function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_lists;
Function fx;
template<typename... Args>
functor_function(Args&&... args): fx(std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
auto f = [&](lua_State* L) -> int { return this->call(L);};
return detail::trampoline(L, f);
}
};
template<typename T, typename Function>
struct member_function : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_lists;
struct functor {
function_type invocation;
T member;
template<typename F, typename... Args>
functor(F&& f, Args&&... args): invocation(std::forward<F>(f)), member(std::forward<Args>(args)...) {}
template<typename... Args>
return_type operator()(Args&&... args) {
auto& mem = detail::unwrap(detail::deref(member));
return (mem.*invocation)(std::forward<Args>(args)...);
}
} fx;
template<typename F, typename... Args>
member_function(F&& f, Args&&... args) : fx(std::forward<F>(f), std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
auto f = [&](lua_State* L) -> int { return this->call(L);};
return detail::trampoline(L, f);
}
};
template<typename T, typename Function>
struct member_variable : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef typename meta::bind_traits<function_type>::return_type return_type;
typedef typename meta::bind_traits<function_type>::args_list args_lists;
function_type var;
T member;
typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M;
template<typename V, typename... Args>
member_variable(V&& v, Args&&... args): var(std::forward<V>(v)), member(std::forward<Args>(args)...) {}
int set_assignable(std::false_type, lua_State* L, M) {
lua_pop(L, 1);
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
}
int set_assignable(std::true_type, lua_State* L, M mem) {
(mem.*var) = stack::get<return_type>(L, 1);
lua_pop(L, 1);
return 0;
}
int set_variable(std::true_type, lua_State* L, M mem) {
return set_assignable(std::is_assignable<std::add_lvalue_reference_t<return_type>, return_type>(), L, mem);
}
int set_variable(std::false_type, lua_State* L, M) {
lua_pop(L, 1);
return luaL_error(L, "sol: cannot write to a const variable");
}
int call(lua_State* L) {
M mem = detail::unwrap(detail::deref(member));
switch (lua_gettop(L)) {
case 0:
stack::push(L, (mem.*var));
return 1;
case 1:
return set_variable(meta::neg<std::is_const<return_type>>(), L, mem);
default:
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
}
}
virtual int operator()(lua_State* L) override {
auto f = [&](lua_State* L) -> int { return this->call(L);};
return detail::trampoline(L, f);
}
};
} // function_detail
} // sol
#endif // SOL_FUNCTION_TYPES_MEMBER_HPP

View File

@ -29,7 +29,7 @@
namespace sol {
namespace function_detail {
template <typename... Functions>
struct overloaded_function : base_function {
struct overloaded_function {
typedef std::tuple<Functions...> overload_list;
typedef std::make_index_sequence<sizeof...(Functions)> indices;
overload_list overloads;
@ -43,12 +43,12 @@ namespace sol {
}
template <typename Fx, std::size_t I, typename... R, typename... Args>
int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
int call(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int) {
auto& func = std::get<I>(overloads);
return stack::call_into_lua<0, false>(r, a, L, start, func);
return call_detail::call_wrapped<void, false, false>(L, func);
}
virtual int operator()(lua_State* L) override {
int operator()(lua_State* L) {
auto mfx = [&](auto&&... args) { return this->call(std::forward<decltype(args)>(args)...); };
return call_detail::overload_match<Functions...>(mfx, L, 1);
}

View File

@ -0,0 +1,139 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FUNCTION_TYPES_STATEFUL_HPP
#define SOL_FUNCTION_TYPES_STATEFUL_HPP
#include "function_types_core.hpp"
namespace sol {
namespace function_detail {
template<typename Func>
struct functor_function {
typedef meta::unwrapped_t<meta::unqualified_t<Func>> Function;
typedef decltype(&Function::operator()) function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_lists;
Function fx;
template<typename... Args>
functor_function(Function f, Args&&... args) : fx(std::move(f), std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
int operator()(lua_State* L) {
auto f = [&](lua_State* L) -> int { return this->call(L); };
return detail::trampoline(L, f);
}
};
template<typename T, typename Function>
struct member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_lists;
struct functor {
function_type invocation;
T member;
template<typename... Args>
functor(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward<Args>(args)...) {}
template<typename... Args>
return_type operator()(Args&&... args) {
auto& mem = detail::unwrap(detail::deref(member));
return (mem.*invocation)(std::forward<Args>(args)...);
}
} fx;
template<typename... Args>
member_function(function_type f, Args&&... args) : fx(std::move(f), std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
int operator()(lua_State* L) {
auto f = [&](lua_State* L) -> int { return this->call(L); };
return detail::trampoline(L, f);
}
~member_function() {
}
};
template<typename T, typename Function>
struct member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef typename meta::bind_traits<function_type>::return_type return_type;
typedef typename meta::bind_traits<function_type>::args_list args_lists;
function_type var;
T member;
typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M;
template<typename... Args>
member_variable(function_type v, Args&&... args) : var(std::move(v)), member(std::forward<Args>(args)...) {}
int set_assignable(std::false_type, lua_State* L, M) {
lua_pop(L, 1);
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
}
int set_assignable(std::true_type, lua_State* L, M mem) {
(mem.*var) = stack::get<return_type>(L, 1);
lua_pop(L, 1);
return 0;
}
int set_variable(std::true_type, lua_State* L, M mem) {
return set_assignable(std::is_assignable<std::add_lvalue_reference_t<return_type>, return_type>(), L, mem);
}
int set_variable(std::false_type, lua_State* L, M) {
lua_pop(L, 1);
return luaL_error(L, "sol: cannot write to a const variable");
}
int call(lua_State* L) {
M mem = detail::unwrap(detail::deref(member));
switch (lua_gettop(L)) {
case 0:
stack::push(L, (mem.*var));
return 1;
case 1:
return set_variable(meta::neg<std::is_const<return_type>>(), L, mem);
default:
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
}
}
int operator()(lua_State* L) {
auto f = [&](lua_State* L) -> int { return this->call(L); };
return detail::trampoline(L, f);
}
};
} // function_detail
} // sol
#endif // SOL_FUNCTION_TYPES_STATEFUL_HPP

View File

@ -19,8 +19,8 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_FUNCTION_TYPES_BASIC_HPP
#define SOL_FUNCTION_TYPES_BASIC_HPP
#ifndef SOL_FUNCTION_TYPES_STATELESS_HPP
#define SOL_FUNCTION_TYPES_STATELESS_HPP
#include "stack.hpp"
@ -147,12 +147,7 @@ namespace sol {
// idx 1...n: verbatim data of member variable pointer
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
function_type& memfx = memberdata.first;
auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type {
auto& item = stack::get<T>(L, 1);
return (item.*memfx)(std::forward<decltype(args)>(args)...);
};
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 2, fx);
return n;
return call_detail::call_wrapped<T, false, false>(L, memfx);
}
static int call(lua_State* L) {
@ -199,4 +194,4 @@ namespace sol {
} // function_detail
} // sol
#endif // SOL_FUNCTION_TYPES_BASIC_HPP
#endif // SOL_FUNCTION_TYPES_STATELESS_HPP

View File

@ -38,7 +38,7 @@ namespace sol {
template <typename... Args>
decltype(auto) overload(Args&&... args) {
return overload_set<Args...>(std::forward<Args>(args)...);
return overload_set<std::decay_t<Args>...>(std::forward<Args>(args)...);
}
}

41
sol/protect.hpp Normal file
View File

@ -0,0 +1,41 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_PROTECT_HPP
#define SOL_PROTECT_HPP
#include <utility>
namespace sol {
template <typename T>
struct protect_t {
T value;
};
template <typename T>
auto protect(T&& value) {
return protect_t<std::decay_t<T>>{ std::forward<T>(value) };
}
} // sol
#endif // SOL_PROTECT_HPP

View File

@ -64,6 +64,11 @@ namespace sol {
inline std::unique_ptr<T, Dx> make_unique_deleter(Args&&... args) {
return std::unique_ptr<T, Dx>(new T(std::forward<Args>(args)...));
}
template <typename T, typename List>
struct constructors_for {
List l;
};
} // detail
template <typename... Args>

View File

@ -0,0 +1,142 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_SIMPLE_USERTYPE_METATABLE_HPP
#define SOL_SIMPLE_USERTYPE_METATABLE_HPP
#include "usertype_metatable.hpp"
#include "object.hpp"
#include <vector>
#include <utility>
namespace sol {
struct simple_tag {} const simple;
template <typename T>
struct simple_usertype_metatable : usertype_detail::registrar {
std::vector<std::pair<object, object>> registrations;
object callconstructfunc;
template <typename N, typename F>
void add(lua_State* L, N&& n, F&& f) {
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, std::forward<F>(f)));
}
template <typename N, typename... Fxs>
void add(lua_State* L, N&& n, constructor_wrapper<Fxs...> c) {
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, detail::constructors_for<T, constructor_wrapper<Fxs...>>{std::move(c)}));
}
template <typename N, typename... Lists>
void add(lua_State* L, N&& n, constructor_list<Lists...> c) {
registrations.emplace_back(make_object(L, std::forward<N>(n)), make_object(L, detail::constructors_for<T, constructor_list<Lists...>>{std::move(c)}));
}
template <typename F>
void add(lua_State* L, call_construction, F&& f) {
callconstructfunc = make_object(L, std::forward<F>(f));
}
template<std::size_t... I, typename Tuple>
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
: callconstructfunc(nil) {
registrations.reserve(std::tuple_size<meta::unqualified_t<Tuple>>::value);
detail::swallow{ 0,
(add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)...
};
}
template<typename... Args>
simple_usertype_metatable(usertype_detail::verified_tag v, lua_State* L, 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(usertype_detail::add_destructor_tag, lua_State* L, Args&&... args) : simple_usertype_metatable(usertype_detail::verified, L, std::forward<Args>(args)..., "__gc", default_destructor) {}
template<typename... Args>
simple_usertype_metatable(usertype_detail::check_destructor_tag, lua_State* L, Args&&... args) : simple_usertype_metatable(meta::condition<meta::all<std::is_destructible<T>, meta::neg<usertype_detail::has_destructor<Args...>>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), L, std::forward<Args>(args)...) {}
public:
template<typename... Args>
simple_usertype_metatable(lua_State* L, Args&&... args) : simple_usertype_metatable(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<usertype_detail::has_constructor<Args...>>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), L, std::forward<Args>(args)...) {}
template<typename... Args, typename... CArgs>
simple_usertype_metatable(constructors<CArgs...> constructorlist, lua_State* L, Args&&... args) : simple_usertype_metatable(usertype_detail::check_destructor_tag(), L, std::forward<Args>(args)..., "new", constructorlist) {}
template<typename... Args, typename... Fxs>
simple_usertype_metatable(constructor_wrapper<Fxs...> constructorlist, lua_State* L, Args&&... args) : simple_usertype_metatable(usertype_detail::check_destructor_tag(), L, std::forward<Args>(args)..., "new", constructorlist) {}
virtual int push_um(lua_State* L) override {
return stack::push(L, std::move(*this));
}
};
namespace stack {
template <typename T>
struct pusher<simple_usertype_metatable<T>> {
typedef simple_usertype_metatable<T> umt_t;
static int push(lua_State* L, umt_t&& umx) {
for (std::size_t i = 0; i < 3; ++i) {
// Pointer types, AKA "references" from C++
const char* metakey = nullptr;
switch (i) {
case 0:
metakey = &usertype_traits<T*>::metatable[0];
break;
case 1:
metakey = &usertype_traits<detail::unique_usertype<T>>::metatable[0];
break;
case 2:
default:
metakey = &usertype_traits<T>::metatable[0];
break;
}
luaL_newmetatable(L, metakey);
stack_reference t(L, -1);
for (auto& kvp : umx.registrations) {
stack::set_field(L, kvp.first, kvp.second, t.stack_index());
}
// Metatable indexes itself
stack::set_field(L, meta_function::index, t, t.stack_index());
// metatable on the metatable
// for call constructor purposes and such
lua_createtable(L, 0, 1);
stack_reference metabehind(L, -1);
if (umx.callconstructfunc.valid()) {
stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
}
stack::set_field(L, metatable_key, metabehind, t.stack_index());
metabehind.pop();
if (i < 2)
t.pop();
}
return 1;
}
};
} // stack
} // sol
#endif // SOL_SIMPLE_USERTYPE_METATABLE_HPP

View File

@ -61,7 +61,7 @@ namespace sol {
typedef std::array<void*, data_t_count> data_t;
data_t voiddata{ {} };
for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[i] = get<lightuserdata_value>(L, up_value_index(index++));
voiddata[i] = get<lightuserdata_value>(L, upvalue_index(index++));
}
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}

View File

@ -92,6 +92,10 @@ namespace sol {
typedef T& type;
};
template <typename T>
struct strip<user<T>> {
typedef T& type;
};
template <typename T>
struct strip<non_null<T>> {
typedef T type;
};
@ -207,7 +211,7 @@ namespace sol {
template <typename T>
inline int alloc_destroy(lua_State* L) {
void* rawdata = lua_touserdata(L, up_value_index(1));
void* rawdata = lua_touserdata(L, upvalue_index(1));
T* data = static_cast<T*>(rawdata);
std::allocator<T> alloc;
alloc.destroy(data);

View File

@ -283,8 +283,9 @@ namespace sol {
static int push_with(lua_State* L, Args&&... args) {
// A dumb pusher
void* rawdata = lua_newuserdata(L, sizeof(T));
T* data = static_cast<T*>(rawdata);
std::allocator<T> alloc;
alloc.construct(static_cast<T*>(rawdata), std::forward<Args>(args)...);
alloc.construct(data, std::forward<Args>(args)...);
if (with_meta) {
lua_CFunction cdel = stack_detail::alloc_destroy<T>;
// Make sure we have a plain GC set for this data
@ -297,6 +298,11 @@ namespace sol {
return 1;
}
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
return push_with(L, std::forward<Args>(args)...);
}
static int push(lua_State* L, const user<T>& u) {
return push_with(L, u.value);
}

View File

@ -331,15 +331,33 @@ namespace sol {
return *this;
}
template<bool read_only = true, typename... Args>
state_view& new_enum(const std::string& name, Args&&... args) {
global.new_enum<read_only>(name, std::forward<Args>(args)...);
template<typename Class, typename... CArgs, typename... Args>
state_view& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
global.new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
return *this;
}
template<typename Class, typename... Args>
state_view& new_simple_usertype(const std::string& name, Args&&... args) {
global.new_simple_usertype<Class>(name, std::forward<Args>(args)...);
return *this;
}
template<typename Class, typename CTor0, typename... CTor, typename... Args>
state_view& new_simple_usertype(const std::string& name, Args&&... args) {
global.new_simple_usertype<Class, CTor0, CTor...>(name, std::forward<Args>(args)...);
return *this;
}
template<typename Class, typename... CArgs, typename... Args>
state_view& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
global.new_usertype<Class>(name, ctor, std::forward<Args>(args)...);
state_view& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
global.new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...);
return *this;
}
template<bool read_only = true, typename... Args>
state_view& new_enum(const std::string& name, Args&&... args) {
global.new_enum<read_only>(name, std::forward<Args>(args)...);
return *this;
}

View File

@ -272,6 +272,26 @@ namespace sol {
return *this;
}
template<typename Class, typename... Args>
basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) {
usertype<Class> utype(simple, base_t::lua_state(), std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template<typename Class, typename CTor0, typename... CTor, typename... Args>
basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) {
constructors<types<CTor0, CTor...>> ctor{};
return new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...);
}
template<typename Class, typename... CArgs, typename... Args>
basic_table_core& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) {
usertype<Class> utype(simple, base_t::lua_state(), ctor, std::forward<Args>(args)...);
set_usertype(name, utype);
return *this;
}
template<bool read_only = true, typename... Args>
basic_table_core& new_enum(const std::string& name, Args&&... args) {
if (read_only) {

View File

@ -168,9 +168,9 @@ namespace sol {
template<typename... Args>
struct function_sig {};
struct up_value_index {
struct upvalue_index {
int index;
up_value_index(int idx) : index(lua_upvalueindex(idx)) {}
upvalue_index(int idx) : index(lua_upvalueindex(idx)) {}
operator int() const { return index; }
};
@ -213,9 +213,10 @@ namespace sol {
struct user {
U value;
user(U x) : value(std::forward<U>(x)) {}
user(U x) : value(std::move(x)) {}
operator U* () { return std::addressof(value); }
operator U& () { return value; }
operator const U& () const { return value; }
};
template <typename T>
@ -611,12 +612,16 @@ namespace sol {
|| meta::is_specialization_of<std::pair, meta::unqualified_t<T>>::value
> { };
template <typename T>
struct is_lua_primitive<T*> : std::true_type {};
template <typename T>
struct is_lua_primitive<std::reference_wrapper<T>> : std::true_type { };
template <typename T>
struct is_lua_primitive<optional<T>> : std::true_type {};
struct is_lua_primitive<user<T>> : std::true_type { };
template <typename T>
struct is_lua_primitive<T*> : std::true_type {};
struct is_lua_primitive<light<T>> : is_lua_primitive<T*> { };
template <typename T>
struct is_lua_primitive<optional<T>> : std::true_type {};
template <>
struct is_lua_primitive<userdata_value> : std::true_type {};
template <>

View File

@ -22,79 +22,54 @@
#ifndef SOL_USERTYPE_HPP
#define SOL_USERTYPE_HPP
#include "usertype_metatable.hpp"
#include "stack.hpp"
#include "usertype_metatable.hpp"
#include "simple_usertype_metatable.hpp"
#include <memory>
namespace sol {
namespace usertype_detail {
struct add_destructor_tag {};
struct check_destructor_tag {};
struct verified_tag {} const verified {};
template <typename T>
struct is_constructor : std::false_type {};
template<typename T>
class usertype {
private:
std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister;
template <typename... Args>
struct is_constructor<constructors<Args...>> : std::true_type {};
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)...)) {}
template <typename... Args>
struct is_constructor<constructor_wrapper<Args...>> : std::true_type {};
template<typename... Args>
usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) {}
template <>
struct is_constructor<no_construction> : std::true_type {};
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)...) {}
template <typename... Args>
using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>;
public:
template <typename T>
struct is_destructor : std::false_type {};
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)...) {}
template <typename Fx>
struct is_destructor<destructor_wrapper<Fx>> : std::true_type {};
template<typename... Args, typename... CArgs>
usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template <typename... Args>
using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>;
} // usertype_detail
template<typename... Args, typename... Fxs>
usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) {}
template<typename T>
class usertype {
private:
std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister;
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)...)) {}
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)...) ) {}
int push(lua_State* L) {
return metatableregister->push_um(L);
}
};
template<typename... Args>
usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(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)...) {}
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)...) {}
template<typename... Args, typename... CArgs>
usertype(constructors<CArgs...> constructorlist, Args&&... args) : usertype(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) {}
int push(lua_State* L) {
return metatableregister->push_um(L);
}
};
namespace stack {
template<typename T>
struct pusher<usertype<T>> {
static int push(lua_State* L, usertype<T>& user) {
return user.push(L);
}
};
} // stack
namespace stack {
template<typename T>
struct pusher<usertype<T>> {
static int push(lua_State* L, usertype<T>& user) {
return user.push(L);
}
};
} // stack
} // sol
#endif // SOL_USERTYPE_HPP

View File

@ -86,6 +86,36 @@ namespace sol {
else
return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
}
struct add_destructor_tag {};
struct check_destructor_tag {};
struct verified_tag {} const verified{};
struct simple_tag {} const simple;
template <typename T>
struct is_constructor : std::false_type {};
template <typename... Args>
struct is_constructor<constructors<Args...>> : std::true_type {};
template <typename... Args>
struct is_constructor<constructor_wrapper<Args...>> : std::true_type {};
template <>
struct is_constructor<no_construction> : 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>>...>;
} // usertype_detail
template <typename T>
@ -148,7 +178,7 @@ namespace sol {
}
template <std::size_t Idx, typename F>
void make_regs(regs_t&, int&, sol::call_construction, F&&) {
void make_regs(regs_t&, int&, call_construction, F&&) {
callconstructfunc = call<Idx + 1>;
secondarymeta = true;
}
@ -228,7 +258,7 @@ namespace sol {
}
static int real_index_call(lua_State* L) {
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, upvalue_index(1));
if (stack::get<type>(L, -1) == type::string) {
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, -1);
bool found = false;
@ -242,7 +272,7 @@ namespace sol {
}
static int real_new_index_call(lua_State* L) {
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, upvalue_index(1));
if (stack::get<type>(L, -2) == type::string) {
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, -2);
bool found = false;
@ -257,7 +287,7 @@ namespace sol {
template <std::size_t Idx, bool is_index = true, bool is_variable = false>
static int real_call(lua_State* L) {
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, upvalue_index(1));
return real_call_with<Idx, is_index, is_variable>(L, f);
}

View File

@ -827,7 +827,7 @@ TEST_CASE("functions/overloading", "Check if overloading works properly for regu
lua.open_libraries(sol::lib::base);
lua.set_function("func_1", func_1);
lua.set_function("func", sol::overload(func_1, func_1s, func_2, func_3));
lua.set_function("func", sol::overload(func_2, func_3, func_1, func_1s));
const std::string string_bark = "string: bark";

85
test_simple_usertype.cpp Normal file
View File

@ -0,0 +1,85 @@
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>
#include <mutex>
TEST_CASE("usertypes/simple_usertypes", "Ensure that simple usertypes properly work here") {
struct marker {
bool value = false;
};
struct bark {
int var = 50;
marker mark;
void fun() {
var = 51;
}
int get() const {
return var;
}
int set(int x) {
var = x;
return var;
}
std::string special() const {
return mark.value ? "woof" : "pantpant";
}
const marker& the_marker() const {
return mark;
}
};
sol::state lua;
lua.new_simple_usertype<bark>("bark",
"fun", &bark::fun,
"get", &bark::get,
"var", &bark::var,
"the_marker", &bark::the_marker,
"x", sol::property(&bark::get),
"y", sol::property(&bark::set),
"z", sol::property(&bark::get, &bark::set)
);
lua.script("b = bark.new()");
bark& b = lua["b"];
lua.script("b:fun()");
int var = b.var;
REQUIRE(var == 51);
lua.script("b:var(20)");
lua.script("v = b:var()");
int v = lua["v"];
REQUIRE(v == 20);
lua.script("m = b:the_marker()");
marker& m = lua["m"];
REQUIRE_FALSE(b.mark.value);
REQUIRE_FALSE(m.value);
m.value = true;
REQUIRE(&b.mark == &m);
REQUIRE(b.mark.value);
sol::table barktable = lua["bark"];
barktable["special"] = &bark::special;
lua.script("s = b:special()");
std::string s = lua["s"];
REQUIRE(s == "woof");
lua.script("b:y(24)");
lua.script("x = b:x()");
int x = lua["x"];
REQUIRE(x == 24);
lua.script("z = b:z(b:z() + 5)");
int z = lua["z"];
REQUIRE(z == 29);
}

View File

@ -664,6 +664,35 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
REQUIRE_THROWS(lua.script("r:func(1,2,'meow')"));
}
TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") {
struct overloading_test {
int print(int i) { std::cout << "Integer print: " << i << std::endl; return 500 + i; }
int print() { std::cout << "No param print." << std::endl; return 500; }
};
sol::state lua;
lua.new_usertype<overloading_test>("overloading_test", sol::constructors<>(),
"print", sol::overload(static_cast<int (overloading_test::*)(int)>(&overloading_test::print), static_cast<int (overloading_test::*)()>(&overloading_test::print)),
"print2", sol::overload(static_cast<int (overloading_test::*)()>(&overloading_test::print), static_cast<int (overloading_test::*)(int)>(&overloading_test::print))
);
lua.set("test", overloading_test());
sol::function f0_0 = lua.load("return test:print()");
sol::function f0_1 = lua.load("return test:print2()");
sol::function f1_0 = lua.load("return test:print(24)");
sol::function f1_1 = lua.load("return test:print2(24)");
int res = f0_0();
int res2 = f0_1();
int res3 = f1_0();
int res4 = f1_1();
REQUIRE(res == 500);
REQUIRE(res2 == 500);
REQUIRE(res3 == 524);
REQUIRE(res4 == 524);
}
TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles properly and errors out at runtime") {
struct bark {
int var = 50;
@ -1015,8 +1044,7 @@ print(e.bark)
}
TEST_CASE("usertype/copyability", "make sure user can write to a class variable even if the class itself isn't copy-safe") {
struct NoCopy
{
struct NoCopy {
int get() const { return _you_can_copy_me; }
void set(int val) { _you_can_copy_me = val; }
@ -1034,3 +1062,26 @@ nocopy.val = 5
)__")
);
}
TEST_CASE("usertype/protect", "users should be allowed to manually protect a function") {
struct protect_me {
int gen(int x) {
return x;
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<protect_me>("protect_me",
"gen", sol::protect( &protect_me::gen )
);
REQUIRE_NOTHROW(
lua.script(R"__(
pm = protect_me.new()
value = pcall(pm.gen,pm)
)__");
);
bool value = lua["value"];
REQUIRE_FALSE(value);
}