Okay, cleaned up includes and now the newest feature:

STATEFUL FUNCTIONS!
Any stateful function now works and is properly cleaned up, thanks to some additional metatables that are associated with the function values.
This lays the ground work for class bindings, but that's a far off dream. For now, table retrieval and `operator[]` is what's for dinner.
This commit is contained in:
ThePhD 2013-12-09 14:12:38 -05:00
parent 21142e7e7d
commit 19d01ecd1d
3 changed files with 56 additions and 25 deletions

View File

@ -24,6 +24,7 @@
#include "functional.hpp"
#include "stack.hpp"
#include <memory>
namespace sol {
@ -112,14 +113,25 @@ struct static_object_lua_func {
struct lua_func {
static int call(lua_State* L) {
void* inheritancedata = lua_touserdata(L, lua_upvalueindex(1));
void** pinheritancedata = static_cast<void**>(lua_touserdata(L, lua_upvalueindex(1)));
void* inheritancedata = *pinheritancedata;
if (inheritancedata == nullptr)
throw sol_error("call from lua to c++ function has null data");
lua_func& fx = *static_cast<lua_func*>(inheritancedata);
lua_func* pfx = static_cast<lua_func*>(inheritancedata);
lua_func& fx = *pfx;
int r = fx(L);
return r;
}
static int gc(lua_State* L) {
void** puserdata = static_cast<void**>(lua_touserdata(L, 1));
void* userdata = *puserdata;
lua_func* ptr = static_cast<lua_func*>(userdata);
std::default_delete<lua_func> dx{ };
dx(ptr);
return 0;
}
virtual int operator()(lua_State*) {
throw sol_error("Failure to call specialized wrapped C++ function from lua");
}
@ -152,6 +164,10 @@ struct lambda_lua_func : public lua_func {
stack::push(L, r);
return sizeof...(TRn);
}
~lambda_lua_func() {
}
};
template<typename TFx, typename T = TFx, bool is_member_pointer = std::is_member_function_pointer<TFx>::value>
@ -179,6 +195,10 @@ struct explicit_lua_func : public lua_func {
stack::push(L, std::move(r));
return sizeof...(TRn);
}
~explicit_lua_func() {
}
};
template<typename TFx, typename T>
@ -199,7 +219,7 @@ struct explicit_lua_func<TFx, T, true> : public lua_func {
} fx;
template<typename... FxArgs>
explicit_lua_func(T m, FxArgs&&... fxargs): fx(std::move( m ), std::forward<FxArgs>(fxargs)...) {}
explicit_lua_func(T m, FxArgs&&... fxargs): fx(std::move(m), std::forward<FxArgs>(fxargs)...) {}
virtual int operator()(lua_State* L) override {
return (*this)(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), L);
@ -217,6 +237,10 @@ struct explicit_lua_func<TFx, T, true> : public lua_func {
stack::push(L, r);
return sizeof...(TRn);
}
~explicit_lua_func() {
}
};
} // sol

View File

@ -165,6 +165,17 @@ inline void push(lua_State* L, const std::string& str) {
lua_pushlstring(L, str.c_str(), str.size());
}
template<typename T>
inline void push_user(lua_State* L, T& userdata, const char* metatablekey) {
T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
T& datum = *pdatum;
datum = userdata;
if (metatablekey != nullptr) {
lua_getfield(L, LUA_REGISTRYINDEX, metatablekey);
lua_setmetatable(L, -2);
}
}
template<typename T, size_t N>
inline void push(lua_State* L, const std::array<T, N>& data) {
for (auto&& i : data) {

View File

@ -24,9 +24,7 @@
#include "stack.hpp"
#include "lua_function.hpp"
#include <unordered_map>
#include <array>
#include <memory>
#include <cstring>
namespace sol {
@ -122,7 +120,7 @@ private:
template<typename T, typename TFx, typename TObj>
table& set_lvalue_fx(std::false_type, T&& key, TFx&& fx, TObj&& obj) {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx;
std::unique_ptr<lua_func> sptr(new explicit_lua_func<clean_fx, TObj>(std::forward<TObj>( obj ), std::forward<TFx>(fx)));
std::unique_ptr<lua_func> sptr(new explicit_lua_func<clean_fx, TObj>(std::forward<TObj>(obj), std::forward<TFx>(fx)));
return set_fx(std::forward<T>(key), std::move(sptr));
}
@ -188,33 +186,31 @@ private:
template<typename T>
table& set_fx(T&& key, std::unique_ptr<lua_func> luafunc) {
std::string fkey(key);
std::string metakey("sol.stateful.");
metakey += fkey;
metakey += ".meta";
lua_func* target = luafunc.release();
void* userdata = reinterpret_cast<void*>(target);
lua_CFunction freefunc = &lua_func::call;
const char* freefuncname = fkey.c_str();
const char* metatablename = metakey.c_str();
const luaL_Reg funcreg[2] = {
{ freefuncname, freefunc },
{ nullptr, nullptr }
};
int exists = luaL_newmetatable(state(), metatablename);
lua_pushstring(state(), "__gc");
lua_pushcclosure(state(), &lua_func::gc, 0);
lua_settable(state(), -3);
push();
// Actual function call we want
stack::push( state(), userdata );
stack::push_user(state(), userdata, metatablename);
luaL_setfuncs(state(), funcreg, 1);
lua_pop(state(), 1);
return *this;
}
static int destroyfunc( lua_State* L ) {
void* userdata = lua_touserdata( L, 1 );
lua_func* ptr = static_cast<lua_func*>( userdata );
std::default_delete<lua_func> dx{ };
dx( ptr );
return 0;
}
};
} // sol