mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
okay std::function returns work
i want to use an is_function trait to differentiate classes when they get pushed problem i feel that is_function may capture things not necessarily intended to be function objects right now it is only qualified by pusher<function_t> if change is necessary, then it becomes pusher<T, EnableIf<IsFunction<T>>>
This commit is contained in:
parent
736d354861
commit
3306b44162
148
sol/function.hpp
148
sol/function.hpp
|
@ -26,6 +26,7 @@
|
|||
#include "tuple.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "userdata_traits.hpp"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
@ -86,49 +87,48 @@ public:
|
|||
namespace stack {
|
||||
template <>
|
||||
struct pusher<function_t> {
|
||||
template<typename T, typename TFx>
|
||||
void set_isfunction_fx(lua_State* L, std::true_type, T&& key, TFx&& fx) {
|
||||
set_fx(std::false_type(), std::forward<T>(key), std::forward<TFx>(fx));
|
||||
|
||||
template<typename TFx>
|
||||
static void set_isfunction_fx(std::true_type, lua_State* L, TFx&& fx) {
|
||||
set_fx(std::false_type(), L, std::forward<TFx>(fx));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx>
|
||||
void set_isfunction_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) {
|
||||
template<typename TFx>
|
||||
static void set_isfunction_fx(std::false_type, lua_State* L, TFx&& fx) {
|
||||
typedef Decay<TFx> clean_lambda;
|
||||
typedef typename function_traits<decltype(&clean_lambda::operator())>::free_function_pointer_type raw_func_t;
|
||||
typedef std::is_convertible<clean_lambda, raw_func_t> isconvertible;
|
||||
set_isconvertible_fx(isconvertible(), std::forward<T>(key), std::forward<TFx>(fx));
|
||||
typedef std::is_convertible<clean_lambda, raw_func_t> is_convertible;
|
||||
set_isconvertible_fx(is_convertible(), L, std::forward<TFx>(fx));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx>
|
||||
void set_isconvertible_fx(lua_State* L, std::true_type, T&& key, TFx&& fx) {
|
||||
template<typename TFx>
|
||||
static void set_isconvertible_fx(std::true_type, lua_State* L, TFx&& fx) {
|
||||
typedef Decay<TFx> clean_lambda;
|
||||
typedef typename function_traits<decltype(&clean_lambda::operator())>::free_function_pointer_type raw_func_t;
|
||||
set_isfunction_fx(std::true_type(), std::forward<T>(key), raw_func_t(std::forward<TFx>(fx)));
|
||||
set_isfunction_fx(std::true_type(), L, raw_func_t(std::forward<TFx>(fx)));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx>
|
||||
void set_isconvertible_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) {
|
||||
template<typename TFx>
|
||||
static void set_isconvertible_fx(std::false_type, lua_State* L, TFx&& fx) {
|
||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
||||
std::unique_ptr<base_function> sptr(new functor_function<clean_fx>(std::forward<TFx>(fx)));
|
||||
set_fx(std::forward<T>(key), std::move(sptr));
|
||||
set_fx<TFx>(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx, typename TObj>
|
||||
void set_lvalue_fx(lua_State* L, std::true_type, T&& key, TFx&& fx, TObj&& obj) {
|
||||
set_fx(std::true_type(), std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||
template<typename TFx, typename TObj>
|
||||
static void set_lvalue_fx(std::true_type, lua_State* L, TFx&& fx, TObj&& obj) {
|
||||
set_fx(std::true_type(), L, std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx, typename TObj>
|
||||
void set_lvalue_fx(lua_State* L, std::false_type, T&& key, TFx&& fx, TObj&& obj) {
|
||||
template<typename TFx, typename TObj>
|
||||
static void set_lvalue_fx(std::false_type, lua_State* L, TFx&& fx, TObj&& obj) {
|
||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
||||
std::unique_ptr<base_function> sptr(new member_function<clean_fx, TObj>(std::forward<TObj>(obj), std::forward<TFx>(fx)));
|
||||
return set_fx(std::forward<T>(key), std::move(sptr));
|
||||
return set_fx<TFx>(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx, typename TObj>
|
||||
void set_fx(lua_State* L, std::true_type, T&& key, TFx&& fx, TObj&& obj) {
|
||||
std::string fkey(key);
|
||||
|
||||
template<typename TFx, typename TObj>
|
||||
static void set_fx(std::true_type, lua_State* L, TFx&& fx, TObj&& obj) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member function pointer
|
||||
// idx n + 1: is the object's void pointer
|
||||
|
@ -137,85 +137,24 @@ struct pusher<function_t> {
|
|||
Decay<TFx> fxptr(std::forward<TFx>(fx));
|
||||
void* userobjdata = static_cast<void*>(sol::detail::get_ptr(obj));
|
||||
lua_CFunction freefunc = &static_member_function<Decay<TObj>, TFx>::call;
|
||||
const char* freefuncname = fkey.c_str();
|
||||
const luaL_Reg funcreg[2] = {
|
||||
{ freefuncname, freefunc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
|
||||
int upvalues = stack::detail::push_as_upvalues(L, fxptr);
|
||||
stack::push(L, userobjdata);
|
||||
luaL_setfuncs(L, funcreg, upvalues + 1);
|
||||
|
||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
template<typename T, typename TFx>
|
||||
void set_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) {
|
||||
std::string fkey(key);
|
||||
template<typename TFx>
|
||||
static void set_fx(lua_State* L, std::false_type, TFx&& fx) {
|
||||
Decay<TFx> target(std::forward<TFx>(fx));
|
||||
lua_CFunction freefunc = &static_function<TFx>::call;
|
||||
const char* freefuncname = fkey.c_str();
|
||||
const luaL_Reg funcreg[2] = {
|
||||
{ freefuncname, freefunc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
int upvalues = stack::detail::push_as_upvalues(L, target);
|
||||
luaL_setfuncs(L, funcreg, upvalues);
|
||||
|
||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set_fx(lua_State* L, T&& key, std::unique_ptr<base_function> luafunc) {
|
||||
std::string fkey(key);
|
||||
std::string metakey("sol.stateful.");
|
||||
metakey += fkey;
|
||||
metakey += ".meta";
|
||||
base_function* target = luafunc.release();
|
||||
void* userdata = reinterpret_cast<void*>(target);
|
||||
lua_CFunction freefunc = &base_function::call;
|
||||
const char* freefuncname = fkey.c_str();
|
||||
const char* metatablename = metakey.c_str();
|
||||
const luaL_Reg funcreg[2] = {
|
||||
{ freefuncname, freefunc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
if (luaL_newmetatable(L, metatablename) == 1) {
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushcclosure(L, &base_function::gc, 0);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stack::detail::push_userdata(L, userdata, metatablename);
|
||||
luaL_setfuncs(L, funcreg, 1);
|
||||
}
|
||||
|
||||
template<typename T, typename TFx>
|
||||
void set_function(T&& key, TFx&& fx) {
|
||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
||||
set_isfunction_fx(std::is_function<clean_fx>(), std::forward<T>(key), std::forward<TFx>(fx));
|
||||
}
|
||||
|
||||
template<typename T, typename TFx, typename TObj>
|
||||
void set_function(T&& key, TFx&& fx, TObj&& obj) {
|
||||
set_lvalue_fx(Bool<std::is_lvalue_reference<TObj>::value || std::is_pointer<TObj>::value>(),
|
||||
std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||
}
|
||||
|
||||
template <typename Key, typename... Args>
|
||||
void push(lua_State* L, Key&& key, Args&&... args) {
|
||||
set_function(L, std::forward<Key>(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
};
|
||||
template <typename Signature>
|
||||
struct pusher<std::function<Signature>> {
|
||||
typedef std::function<Signature> fx_t;
|
||||
|
||||
static void push_fx(lua_State* L, std::unique_ptr<base_function> luafunc) {
|
||||
auto&& metakey = userdata_traits<fx_t>::metatable;
|
||||
template<typename TFx>
|
||||
static void set_fx(lua_State* L, std::unique_ptr<base_function> luafunc) {
|
||||
auto&& metakey = userdata_traits<Unqualified<TFx>>::metatable;
|
||||
const char* metatablename = std::addressof(metakey[0]);
|
||||
base_function* target = luafunc.release();
|
||||
void* userdata = reinterpret_cast<void*>(target);
|
||||
|
@ -223,17 +162,36 @@ struct pusher<std::function<Signature>> {
|
|||
|
||||
if (luaL_newmetatable(L, metatablename) == 1) {
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushcclosure(L, &base_function::gc, 0);
|
||||
stack::push(L, &base_function::gc);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
stack::detail::push_userdata(L, userdata, metatablename);
|
||||
lua_pushcclosure(L, freefunc, 1);
|
||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, 1);
|
||||
}
|
||||
|
||||
template<typename TFx>
|
||||
static void set_function(lua_State* L, TFx&& fx) {
|
||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
||||
set_isfunction_fx(std::is_function<clean_fx>(), L, std::forward<TFx>(fx));
|
||||
}
|
||||
|
||||
template<typename TFx, typename TObj>
|
||||
static void set_function(lua_State* L, TFx&& fx, TObj&& obj) {
|
||||
set_lvalue_fx(Bool<std::is_lvalue_reference<TObj>::value || std::is_pointer<TObj>::value>(),
|
||||
L, std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void push(lua_State* L, Args&&... args) {
|
||||
set_function(L, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Signature>
|
||||
struct pusher<std::function<Signature>> {
|
||||
static void push(lua_State* L, std::function<Signature> fx) {
|
||||
std::unique_ptr<base_function> sptr(new functor_function<fx_t>(std::move(fx)));
|
||||
push_fx(L, std::move(sptr));
|
||||
pusher<function_t>{}.push(L, std::move(fx));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user