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:
PrincessNyanara 2014-06-07 09:56:48 -04:00 committed by Rapptz
parent 736d354861
commit 3306b44162

View File

@ -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));
}
};