mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Free functions and lambdas whos first arguments match the userdata type (unqualified)
now are usable as functions for userdata. allows free functions and lambdas to provide useful operations, like operator+*-/ and other things which may not be implemented as class members.
This commit is contained in:
parent
2e44a6cf42
commit
37c3883eb6
|
@ -28,7 +28,7 @@
|
|||
namespace sol {
|
||||
|
||||
struct default_construct {
|
||||
template <typename T, typename... Args>
|
||||
template<typename T, typename... Args>
|
||||
void operator()(T&& obj, Args&&... args) const {
|
||||
std::allocator<Unqualified<T>> alloc{};
|
||||
alloc.construct(obj, std::forward<Args>(args)...);
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
};
|
||||
|
||||
namespace stack {
|
||||
template <typename... Sigs>
|
||||
template<typename... Sigs>
|
||||
struct pusher<function_sig_t<Sigs...>> {
|
||||
|
||||
template<typename R, typename... Args, typename Fx, typename = typename std::result_of<Fx(Args...)>::type>
|
||||
|
@ -208,26 +208,26 @@ struct pusher<function_sig_t<Sigs...>> {
|
|||
stack::push(L, freefunc, 1);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
template<typename... Args>
|
||||
static void push(lua_State* L, Args&&... args) {
|
||||
set(L, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Signature>
|
||||
template<typename Signature>
|
||||
struct pusher<std::function<Signature>> {
|
||||
static void push(lua_State* L, std::function<Signature> fx) {
|
||||
pusher<function_t>{}.push(L, std::move(fx));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Signature>
|
||||
template<typename Signature>
|
||||
struct getter<std::function<Signature>> {
|
||||
typedef function_traits<Signature> fx_t;
|
||||
typedef typename fx_t::args_type args_t;
|
||||
typedef typename tuple_types<typename fx_t::return_type>::type ret_t;
|
||||
|
||||
template <typename... FxArgs, typename... Ret>
|
||||
template<typename... FxArgs, typename... Ret>
|
||||
static std::function<Signature> get_std_func(types<FxArgs...>, types<Ret...>, lua_State* L, int index = -1) {
|
||||
typedef typename function_traits<Signature>::return_type return_t;
|
||||
sol::function f(L, index);
|
||||
|
@ -237,7 +237,7 @@ struct getter<std::function<Signature>> {
|
|||
return std::move(fx);
|
||||
}
|
||||
|
||||
template <typename... FxArgs>
|
||||
template<typename... FxArgs>
|
||||
static std::function<Signature> get_std_func(types<FxArgs...>, types<void>, lua_State* L, int index = -1) {
|
||||
sol::function f(L, index);
|
||||
auto fx = [ f, L, index ] (FxArgs&&... args) -> void {
|
||||
|
@ -246,7 +246,7 @@ struct getter<std::function<Signature>> {
|
|||
return std::move(fx);
|
||||
}
|
||||
|
||||
template <typename... FxArgs>
|
||||
template<typename... FxArgs>
|
||||
static std::function<Signature> get_std_func(types<FxArgs...> t, types<>, lua_State* L, int index = -1) {
|
||||
return get_std_func(std::move(t), types<void>(), L, index);
|
||||
}
|
||||
|
|
|
@ -31,8 +31,12 @@ namespace detail {
|
|||
struct ref_call_t {};
|
||||
const auto ref_call = ref_call_t{};
|
||||
|
||||
template <typename T, typename Func, typename R, bool is_variable = std::is_member_object_pointer<Func>::value>
|
||||
template<typename T, typename Func, typename = void>
|
||||
struct functor {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
|
@ -40,46 +44,75 @@ struct functor {
|
|||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
R operator()(Args&&... args) {
|
||||
T& member = *item;
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Func>
|
||||
struct functor<T, Func, void, false> {
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
void operator()(Args&&... args) {
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
(member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(this->call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Func, typename R>
|
||||
struct functor<T, Func, R, true> {
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, typename std::enable_if<std::is_member_object_pointer<Func>::value>::type> {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename Arg, typename... Args>
|
||||
void operator()(Arg&& arg, Args&&...) {
|
||||
template<typename Arg>
|
||||
void operator()(Arg&& arg) {
|
||||
T& member = *item;
|
||||
(member.*invocation) = std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
R operator()() {
|
||||
return_type operator()() {
|
||||
T& member = *item;
|
||||
return (member.*invocation);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, typename std::enable_if<std::is_function<Func>::value || std::is_class<Func>::value>::type> {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef remove_one_type<typename traits_type::args_type> args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef typename std::conditional<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, typename std::add_pointer<Func>::type>::type function_type;
|
||||
T* item;
|
||||
function_type invocation;
|
||||
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
invocation(member, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return invocation(member, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(this->call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // detail
|
||||
|
||||
|
||||
|
@ -340,11 +373,12 @@ template<typename Function, typename Tp>
|
|||
struct userdata_function_core : public base_function {
|
||||
typedef typename std::remove_pointer<Tp>::type T;
|
||||
typedef typename std::remove_pointer<typename std::decay<Function>::type>::type function_type;
|
||||
typedef member_traits<Function> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef detail::functor<T, function_type> fx_t;
|
||||
typedef typename fx_t::traits_type traits_type;
|
||||
typedef typename fx_t::args_type args_type;
|
||||
typedef typename fx_t::return_type return_type;
|
||||
|
||||
detail::functor<T, function_type, return_type> fx;
|
||||
fx_t fx;
|
||||
|
||||
template<typename... FxArgs>
|
||||
userdata_function_core(FxArgs&&... fxargs): fx(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
@ -398,14 +432,14 @@ template<typename Function, typename Tp>
|
|||
struct userdata_function : public userdata_function_core<Function, Tp> {
|
||||
typedef userdata_function_core<Function, Tp> base_t;
|
||||
typedef typename std::remove_pointer<Tp>::type T;
|
||||
typedef member_traits<Function> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
template<typename... FxArgs>
|
||||
userdata_function(FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template <typename Tx>
|
||||
template<typename Tx>
|
||||
int fx_call(lua_State* L) {
|
||||
this->fx.item = detail::get_ptr(stack::get<Tx>(L, 1));
|
||||
if (this->fx.item == nullptr)
|
||||
|
@ -426,14 +460,14 @@ template<typename Function, typename Tp>
|
|||
struct userdata_variable_function : public userdata_function_core<Function, Tp> {
|
||||
typedef userdata_function_core<Function, Tp> base_t;
|
||||
typedef typename std::remove_pointer<Tp>::type T;
|
||||
typedef member_traits<Function> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
template<typename... FxArgs>
|
||||
userdata_variable_function(FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
template <typename Tx>
|
||||
template<typename Tx>
|
||||
int fx_call (lua_State* L) {
|
||||
this->fx.item = detail::get_ptr(stack::get<Tx>(L, 1));
|
||||
if (this->fx.item == nullptr)
|
||||
|
@ -463,9 +497,9 @@ template<typename Function, typename Tp>
|
|||
struct userdata_indexing_function : public userdata_function_core<Function, Tp> {
|
||||
typedef userdata_function_core<Function, Tp> base_t;
|
||||
typedef typename std::remove_pointer<Tp>::type T;
|
||||
typedef member_traits<Function> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
std::string name;
|
||||
std::unordered_map<std::string, std::pair<std::unique_ptr<base_function>, bool>> functions;
|
||||
|
@ -473,7 +507,7 @@ struct userdata_indexing_function : public userdata_function_core<Function, Tp>
|
|||
template<typename... FxArgs>
|
||||
userdata_indexing_function(std::string name, FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...), name(std::move(name)) {}
|
||||
|
||||
template <typename Tx>
|
||||
template<typename Tx>
|
||||
int fx_call (lua_State* L) {
|
||||
std::string accessor = stack::get<std::string>(L, 1 - lua_gettop(L));
|
||||
auto function = functions.find(accessor);
|
||||
|
|
|
@ -49,7 +49,7 @@ inline T* get_ptr(T* val) {
|
|||
return val;
|
||||
}
|
||||
|
||||
template <typename Decorated>
|
||||
template<typename Decorated>
|
||||
struct return_forward {
|
||||
typedef Unqualified<Decorated> T;
|
||||
|
||||
|
@ -83,12 +83,12 @@ inline void push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) {
|
|||
lua_setmetatable(L, -2);
|
||||
}
|
||||
} // detail
|
||||
template <typename T, typename X = void>
|
||||
template<typename T, typename X = void>
|
||||
struct getter;
|
||||
template <typename T, typename X = void>
|
||||
template<typename T, typename X = void>
|
||||
struct pusher;
|
||||
|
||||
template <typename T, typename>
|
||||
template<typename T, typename>
|
||||
struct getter {
|
||||
template<typename U = T, EnableIf<std::is_floating_point<U>> = 0>
|
||||
static U get(lua_State* L, int index = -1) {
|
||||
|
@ -118,7 +118,7 @@ struct getter {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct getter<T*> {
|
||||
static T* get(lua_State* L, int index = -1) {
|
||||
void* udata = lua_touserdata(L, index);
|
||||
|
@ -127,21 +127,21 @@ struct getter<T*> {
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<type> {
|
||||
static type get(lua_State *L, int index){
|
||||
return static_cast<type>(lua_type(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<bool> {
|
||||
static bool get(lua_State* L, int index) {
|
||||
return lua_toboolean(L, index) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<std::string> {
|
||||
static std::string get(lua_State* L, int index = -1) {
|
||||
std::string::size_type len;
|
||||
|
@ -150,14 +150,14 @@ struct getter<std::string> {
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<const char*> {
|
||||
static const char* get(lua_State* L, int index = -1) {
|
||||
return lua_tostring(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<nil_t> {
|
||||
static nil_t get(lua_State* L, int index = -1) {
|
||||
if (lua_isnil(L, index) == 0)
|
||||
|
@ -166,28 +166,28 @@ struct getter<nil_t> {
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<userdata_t> {
|
||||
static userdata_t get(lua_State* L, int index = -1) {
|
||||
return{ lua_touserdata(L, index) };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<lightuserdata_t> {
|
||||
static lightuserdata_t get(lua_State* L, int index = 1) {
|
||||
return{ lua_touserdata(L, index) };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<upvalue_t> {
|
||||
static upvalue_t get(lua_State* L, int index = 1) {
|
||||
return{ lua_touserdata(L, lua_upvalueindex(index)) };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct getter<void*> {
|
||||
static void* get(lua_State* L, int index = 1) {
|
||||
return lua_touserdata(L, index);
|
||||
|
@ -302,7 +302,7 @@ struct pusher<lightuserdata_t> {
|
|||
|
||||
template<>
|
||||
struct pusher<userdata_t> {
|
||||
template <typename T, typename U = Unqualified<T>>
|
||||
template<typename T, typename U = Unqualified<T>>
|
||||
static void push(lua_State* L, T&& data) {
|
||||
U* userdata = static_cast<U*>(lua_newuserdata(L, sizeof(U)));
|
||||
new(userdata)U(std::forward<T>(data));
|
||||
|
@ -484,7 +484,7 @@ inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
|
|||
return call_syntax::dot;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct get_return {
|
||||
typedef decltype(get<T>(nullptr)) type;
|
||||
};
|
||||
|
|
|
@ -90,9 +90,11 @@ public:
|
|||
|
||||
template<typename Key, typename T>
|
||||
table& set_userdata(Key&& key, userdata<T>& user) {
|
||||
std::string ukey(std::forward<Key>(key));
|
||||
push();
|
||||
stack::push(state(), std::forward<Key>(key));
|
||||
stack::push(state(), user);
|
||||
lua_setglobal(state(), ukey.c_str());
|
||||
lua_settable(state(), -3);
|
||||
lua_pop(state(), 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <functional>
|
||||
|
||||
namespace sol {
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct identity { typedef T type; };
|
||||
|
||||
template<typename... Args>
|
||||
|
@ -36,27 +36,27 @@ struct is_tuple : std::false_type{ };
|
|||
template<typename... Args>
|
||||
struct is_tuple<std::tuple<Args...>> : std::true_type{ };
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct unwrap {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct unwrap<std::reference_wrapper<T>> {
|
||||
typedef typename std::add_lvalue_reference<T>::type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct remove_member_pointer;
|
||||
|
||||
template <typename R, typename T>
|
||||
template<typename R, typename T>
|
||||
struct remove_member_pointer<R T::*> {
|
||||
typedef R type;
|
||||
};
|
||||
|
||||
template <typename T, template <typename...> class Templ>
|
||||
template<typename T, template<typename...> class Templ>
|
||||
struct is_specialization_of : std::false_type { };
|
||||
template <typename... T, template <typename...> class Templ>
|
||||
template<typename... T, template<typename...> class Templ>
|
||||
struct is_specialization_of<Templ<T...>, Templ> : std::true_type { };
|
||||
|
||||
template<class T, class...>
|
||||
|
@ -104,7 +104,7 @@ using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::t
|
|||
template<typename T>
|
||||
using Decay = typename std::decay<T>::type;
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
using Unwrap = typename unwrap<T>::type;
|
||||
|
||||
template<typename... Args>
|
||||
|
@ -160,26 +160,23 @@ struct check_deducible_signature {
|
|||
template<class F>
|
||||
struct has_deducible_signature : detail::check_deducible_signature<F>::type { };
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
using has_deducible_signature_t = typename has_deducible_signature<T>::type;
|
||||
|
||||
template<typename T>
|
||||
struct Function : Bool<detail::is_function_impl<T>::value> {};
|
||||
|
||||
template<typename TFuncSignature>
|
||||
struct function_traits;
|
||||
namespace detail {
|
||||
template<typename Signature, bool b = std::is_class<Signature>::value>
|
||||
struct fx_traits;
|
||||
|
||||
template <typename TFuncSignature>
|
||||
using function_args_t = typename function_traits<TFuncSignature>::args_type;
|
||||
template<typename Signature>
|
||||
struct fx_traits<Signature, true> : fx_traits<decltype(Signature::operator()), false> {
|
||||
|
||||
template <typename TFuncSignature>
|
||||
using function_signature_t = typename function_traits<TFuncSignature>::signature_type;
|
||||
|
||||
template <typename TFuncSignature>
|
||||
using function_return_t = typename function_traits<TFuncSignature>::return_type;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct function_traits<R(T::*)(Args...)> {
|
||||
struct fx_traits<R(T::*)(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = true;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
|
@ -194,7 +191,7 @@ struct function_traits<R(T::*)(Args...)> {
|
|||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct function_traits<R(T::*)(Args...) const> {
|
||||
struct fx_traits<R(T::*)(Args...) const, false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = true;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
|
@ -209,7 +206,7 @@ struct function_traits<R(T::*)(Args...) const> {
|
|||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct function_traits<R(Args...)> {
|
||||
struct fx_traits<R(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = false;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
|
@ -224,7 +221,7 @@ struct function_traits<R(Args...)> {
|
|||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct function_traits<R(*)(Args...)> {
|
||||
struct fx_traits<R(*)(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = false;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
|
@ -238,13 +235,27 @@ struct function_traits<R(*)(Args...)> {
|
|||
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
template<typename Signature>
|
||||
struct function_traits : detail::fx_traits<Signature> {};
|
||||
|
||||
template<typename Signature>
|
||||
using function_args_t = typename function_traits<Signature>::args_type;
|
||||
|
||||
template<typename Signature>
|
||||
using function_signature_t = typename function_traits<Signature>::signature_type;
|
||||
|
||||
template<typename Signature>
|
||||
using function_return_t = typename function_traits<Signature>::return_type;
|
||||
|
||||
namespace detail {
|
||||
template <typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
|
||||
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
|
||||
struct member_traits : function_traits<Signature> {
|
||||
|
||||
};
|
||||
|
||||
template <typename Signature>
|
||||
template<typename Signature>
|
||||
struct member_traits<Signature, true> {
|
||||
typedef typename remove_member_pointer<Signature>::type Arg;
|
||||
typedef typename remove_member_pointer<Signature>::type R;
|
||||
|
@ -262,7 +273,7 @@ struct member_traits<Signature, true> {
|
|||
};
|
||||
} // detail
|
||||
|
||||
template <typename Signature>
|
||||
template<typename Signature>
|
||||
struct member_traits : detail::member_traits<Signature> {
|
||||
|
||||
};
|
||||
|
@ -294,12 +305,12 @@ struct has_key_value_pair_impl {
|
|||
template<typename T>
|
||||
struct has_key_value_pair : decltype(has_key_value_pair_impl::test<T>(0)) {};
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
auto unwrapper(T&& item) -> decltype(std::forward<T>(item)) {
|
||||
return std::forward<T>(item);
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
template<typename Arg>
|
||||
Unwrap<Arg> unwrapper(std::reference_wrapper<Arg> arg) {
|
||||
return arg.get();
|
||||
}
|
||||
|
|
|
@ -58,15 +58,26 @@ struct build_reverse_indices<0, Ns...> : indices<Ns...> {};
|
|||
|
||||
template<typename... Args>
|
||||
struct types : build_indices<sizeof...(Args)> { typedef types type; };
|
||||
|
||||
|
||||
namespace detail {
|
||||
template<class Acc, class... Args>
|
||||
struct reversed_ : Acc{};
|
||||
|
||||
|
||||
template<typename... RArgs, typename Arg, typename... Args>
|
||||
struct reversed_<types<RArgs...>, Arg, Args...> : reversed_<types<Arg, RArgs...>, Args...>{};
|
||||
|
||||
|
||||
template<typename Arg>
|
||||
struct chop_one : types<> {};
|
||||
|
||||
template<typename Arg0, typename Arg1, typename... Args>
|
||||
struct chop_one<types<Arg0, Arg1, Args...>> : types<Arg1, Args...> {};
|
||||
|
||||
template<typename Arg, typename... Args>
|
||||
struct chop_one<types<Arg, Args...>> : types<Args...> {};
|
||||
} // detail
|
||||
|
||||
template<typename... Args>
|
||||
struct reversed : reversed_<types<>, Args...>{};
|
||||
struct reversed : detail::reversed_<types<>, Args...>{};
|
||||
|
||||
template<typename... Args>
|
||||
struct tuple_types : types<Args...> {};
|
||||
|
@ -74,6 +85,9 @@ struct tuple_types : types<Args...> {};
|
|||
template<typename... Args>
|
||||
struct tuple_types<std::tuple<Args...>> : types<Args...> {};
|
||||
|
||||
template<typename Arg>
|
||||
struct remove_one_type : detail::chop_one<Arg> {};
|
||||
|
||||
template<typename... Tn>
|
||||
struct constructors {};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include <lua.hpp>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace sol {
|
||||
struct nil_t {};
|
||||
|
@ -32,7 +32,7 @@ const nil_t nil {};
|
|||
struct void_type {};
|
||||
const void_type Void {};
|
||||
|
||||
template <typename... T>
|
||||
template<typename... T>
|
||||
struct function_sig_t {};
|
||||
using function_t = function_sig_t<>;
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ const std::array<std::string, 19> meta_function_names = {{
|
|||
"__gc",
|
||||
}};
|
||||
|
||||
/* Too easy?
|
||||
enum class meta_function {
|
||||
index,
|
||||
new_index,
|
||||
|
@ -86,7 +85,7 @@ enum class meta_function {
|
|||
equal_to,
|
||||
less_than,
|
||||
less_than_or_equal_to,
|
||||
};*/
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class userdata {
|
||||
|
@ -212,19 +211,56 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
template<std::size_t N, typename TBase, typename Ret>
|
||||
bool build_function(std::true_type, function_map_t*&, function_map_t*&, std::string funcname, Ret TBase::* func) {
|
||||
static_assert(std::is_base_of<TBase, T>::value, "Any registered function must be part of the class");
|
||||
template<std::size_t N, typename Base, typename Ret>
|
||||
bool build_function(std::true_type, function_map_t*&, function_map_t*&, std::string funcname, Ret Base::* func) {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
indexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_variable_function<function_type, T>>(func), false));
|
||||
newindexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_variable_function<function_type, T>>(func), false));
|
||||
return false;
|
||||
}
|
||||
|
||||
template<std::size_t N, typename TBase, typename Ret>
|
||||
bool build_function(std::false_type, function_map_t*& index, function_map_t*& newindex, std::string funcname, Ret TBase::* func) {
|
||||
static_assert(std::is_base_of<TBase, T>::value, "Any registered function must be part of the class");
|
||||
template<typename Arg, typename... Args, typename Ret>
|
||||
std::unique_ptr<base_function> make_function(const std::string&, Ret(*func)(Arg, Args...)) {
|
||||
typedef Unqualified<Arg> Argu;
|
||||
static_assert(std::is_base_of<Argu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
return detail::make_unique<userdata_function<function_type, T>>(func);
|
||||
}
|
||||
|
||||
template<typename Base, typename Ret>
|
||||
std::unique_ptr<base_function> make_variable_function(std::true_type, const std::string&, Ret Base::* func) {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
return detail::make_unique<userdata_variable_function<function_type, T>>(func);
|
||||
}
|
||||
|
||||
template<typename Base, typename Ret>
|
||||
std::unique_ptr<base_function> make_variable_function(std::false_type, const std::string&, Ret Base::* func) {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
return detail::make_unique<userdata_function<function_type, T>>(func);
|
||||
}
|
||||
|
||||
template<typename Base, typename Ret>
|
||||
std::unique_ptr<base_function> make_function(const std::string& name, Ret Base::* func) {
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
return make_variable_function(std::is_member_object_pointer<function_type>(), name, func);
|
||||
}
|
||||
|
||||
template<typename Fx>
|
||||
std::unique_ptr<base_function> make_function(const std::string&, Fx&& func) {
|
||||
typedef Unqualified<Fx> Fxu;
|
||||
typedef typename std::tuple_element<0, typename function_traits<Fxu>::arg_tuple_type>::type TArg;
|
||||
typedef Unqualified<TArg> TArgu;
|
||||
static_assert(std::is_base_of<TArgu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
|
||||
typedef typename std::decay<decltype(func)>::type function_type;
|
||||
return detail::make_unique<userdata_function<function_type, T>>(func);
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Fx>
|
||||
bool build_function(std::false_type, function_map_t*& index, function_map_t*& newindex, std::string funcname, Fx&& func) {
|
||||
typedef typename std::decay<Fx>::type function_type;
|
||||
auto metamethod = std::find(meta_function_names.begin(), meta_function_names.end(), funcname);
|
||||
if (metamethod != meta_function_names.end()) {
|
||||
functionnames.push_back(std::move(funcname));
|
||||
|
@ -246,23 +282,22 @@ private:
|
|||
ptr = std::move(idxptr);
|
||||
}
|
||||
else {
|
||||
ptr = detail::make_unique<userdata_function<function_type, T>>(func);
|
||||
ptr = make_function(funcname, std::forward<Fx>(func));
|
||||
}
|
||||
metafunctions.emplace_back(std::move(ptr));
|
||||
metafunctiontable.push_back( { name.c_str(), &base_function::userdata<N>::call } );
|
||||
ptrmetafunctiontable.push_back( { name.c_str(), &base_function::userdata<N>::ref_call } );
|
||||
return true;
|
||||
}
|
||||
indexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_function<function_type, T>>(func), true ));
|
||||
newindexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_function<function_type, T>>(func), true));
|
||||
indexmetafunctions.emplace(funcname, std::make_pair(make_function(funcname, std::forward<Fx>(func)), true));
|
||||
return false;
|
||||
}
|
||||
|
||||
template<std::size_t N, typename TBase, typename Ret, typename... Args>
|
||||
void build_function_tables(function_map_t*& index, function_map_t*& newindex, std::string funcname, Ret TBase::* func, Args&&... args) {
|
||||
typedef typename std::is_member_object_pointer<decltype(func)>::type is_variable;
|
||||
template<std::size_t N, typename Fx, typename... Args>
|
||||
void build_function_tables(function_map_t*& index, function_map_t*& newindex, std::string funcname, Fx&& func, Args&&... args) {
|
||||
typedef typename std::is_member_object_pointer<Unqualified<Fx>>::type is_variable;
|
||||
static const std::size_t V = static_cast<std::size_t>( !is_variable::value );
|
||||
if (build_function<N>(is_variable(), index, newindex, std::move(funcname), std::move(func))) {
|
||||
if (build_function<N>(is_variable(), index, newindex, std::move(funcname), std::forward<Fx>(func))) {
|
||||
build_function_tables<N + V>(index, newindex, std::forward<Args>(args)...);
|
||||
}
|
||||
else {
|
||||
|
@ -270,13 +305,12 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
/* Apparently there needs to be magic
|
||||
template<std::size_t N, typename TBase, typename Ret, typename... Args>
|
||||
void build_function_tables(function_map_t*& index, function_map_t*& newindex, meta_function metafunc, Ret TBase::* func, Args&&... args) {
|
||||
template<std::size_t N, typename Base, typename Ret, typename... Args>
|
||||
void build_function_tables(function_map_t*& index, function_map_t*& newindex, meta_function metafunc, Ret Base::* func, Args&&... args) {
|
||||
std::size_t idx = static_cast<std::size_t>(metafunc);
|
||||
const std::string& funcname = meta_function_names[idx];
|
||||
build_function_tables<N>(index, newindex, funcname, std::move(func), std::forward<Args>(args)...);
|
||||
}*/
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
|
@ -331,7 +365,7 @@ public:
|
|||
}
|
||||
private:
|
||||
|
||||
template <typename Meta, typename MetaFuncs, typename MetaFuncTable>
|
||||
template<typename Meta, typename MetaFuncs, typename MetaFuncTable>
|
||||
static void push_metatable(lua_State* L, Meta&& metakey, MetaFuncs&& metafuncs, MetaFuncTable&& metafunctable) {
|
||||
luaL_newmetatable(L, std::addressof(metakey[0]));
|
||||
if (metafunctable.size() > 1) {
|
||||
|
@ -355,7 +389,7 @@ private:
|
|||
lua_setglobal(L, std::addressof(userdata_traits<T>::gctable[0]));
|
||||
}
|
||||
|
||||
template <bool release = false, typename TCont>
|
||||
template<bool release = false, typename TCont>
|
||||
static int push_upvalues (lua_State* L, TCont&& cont) {
|
||||
int n = 0;
|
||||
for (auto& c : cont) {
|
||||
|
@ -370,7 +404,7 @@ private:
|
|||
};
|
||||
|
||||
namespace stack {
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
struct pusher<userdata<T>> {
|
||||
static void push (lua_State* L, userdata<T>& user) {
|
||||
user.push(L);
|
||||
|
|
46
tests.cpp
46
tests.cpp
|
@ -160,6 +160,31 @@ struct Vec {
|
|||
}
|
||||
};
|
||||
|
||||
struct giver {
|
||||
int a = 0;
|
||||
|
||||
giver () {
|
||||
|
||||
}
|
||||
|
||||
void gief () {
|
||||
a = 1;
|
||||
}
|
||||
|
||||
static void stuff () {
|
||||
|
||||
}
|
||||
|
||||
static void gief_stuff (giver& t, int a) {
|
||||
t.a = a;
|
||||
}
|
||||
|
||||
~giver () {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TEST_CASE("simple/set_global", "Check if the set_global works properly.") {
|
||||
sol::state lua;
|
||||
|
||||
|
@ -809,3 +834,24 @@ TEST_CASE("userdata/member-variables", "allow table-like accessors to behave as
|
|||
"assert(x == 3)\n"
|
||||
));
|
||||
}
|
||||
|
||||
TEST_CASE("userdata/nonmember functions implement functionality", "let users set non-member functions that take unqualified T as first parameter to userdata") {
|
||||
sol::state lua;
|
||||
lua.open_libraries( sol::lib::base );
|
||||
|
||||
lua.new_userdata<giver>( "giver",
|
||||
"gief_stuff", giver::gief_stuff,
|
||||
"gief", &giver::gief,
|
||||
"__tostring", [](const giver& t) {
|
||||
return std::to_string(t.a) + ": giving value";
|
||||
}
|
||||
).get<sol::table>( "giver" )
|
||||
.set_function( "stuff", giver::stuff );
|
||||
|
||||
REQUIRE_NOTHROW(lua.script("giver.stuff()"));
|
||||
REQUIRE_NOTHROW(lua.script("t = giver.new()\n"
|
||||
"print(tostring(t))\n"
|
||||
"t:gief()\n"
|
||||
"t:gief_stuff(20)\n"));
|
||||
REQUIRE((lua.get<giver>("t").a == 20));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user