mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
userdata<T> now works and compiles on MSVC.
It's going to take serious work to make it happen in GCC, plus the fact that 4.9 is still giving me so many errors I can't even read it... I'll let Rapptz figure it out, but later. Sexy class bindings, yes!
This commit is contained in:
parent
359848f371
commit
2243bec052
118
main.cpp
118
main.cpp
|
@ -1,118 +0,0 @@
|
||||||
#include <sol.hpp>
|
|
||||||
#include <sol/demangle.hpp>
|
|
||||||
|
|
||||||
namespace sol {
|
|
||||||
|
|
||||||
template <typename... Tn>
|
|
||||||
struct constructors;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class lua_class {
|
|
||||||
public:
|
|
||||||
static const std::string classname;
|
|
||||||
static const std::string meta;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string luaname;
|
|
||||||
std::vector<std::string> functionnames;
|
|
||||||
std::vector<class_lua_func> functions;
|
|
||||||
std::vector<luaL_Reg> functiontable;
|
|
||||||
std::vector<luaL_Reg> metatable;
|
|
||||||
|
|
||||||
struct maker {
|
|
||||||
|
|
||||||
static int construct( lua_State* L ) {
|
|
||||||
// First argument is now a table that represent the class to instantiate
|
|
||||||
luaL_checktype( L, 1, LUA_TTABLE );
|
|
||||||
|
|
||||||
lua_newtable( L ); // Create table to represent instance
|
|
||||||
|
|
||||||
// Set first argument of new to metatable of instance
|
|
||||||
lua_pushvalue( L, 1 );
|
|
||||||
lua_setmetatable( L, -2 );
|
|
||||||
|
|
||||||
// Do function lookups in metatable
|
|
||||||
lua_pushvalue( L, 1 );
|
|
||||||
lua_setfield( L, 1, "__index" );
|
|
||||||
|
|
||||||
void* userdata = lua_newuserdata( L, sizeof( T ) );
|
|
||||||
T* obj = static_cast<T*>( userdata );
|
|
||||||
std::allocator<T> alloc{ };
|
|
||||||
alloc.construct( obj );
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t n>
|
|
||||||
static int destruct( lua_State* L ) {
|
|
||||||
void* userdata = lua_touserdata( L, 0 );
|
|
||||||
T* obj = static_cast<T*>( userdata );
|
|
||||||
std::allocator<T> alloc{ };
|
|
||||||
alloc.destroy( obj );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void build_function_tables( ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args, typename Ret, typename... MArgs>
|
|
||||||
void build_function_tables( Ret( T::* func )( MArgs... ), std::string name, Args&&... args ) {
|
|
||||||
functionnames.push_back( std::move( name ) );
|
|
||||||
functions.emplace_back( std::move( func ) );
|
|
||||||
functiontable.push_back( { functionnames.back().c_str(), &lua_func::call } );
|
|
||||||
build_function_tables( std::forward<Args>( args )... );
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <typename... Args>
|
|
||||||
lua_class( Args&&... args ) : lua_class( classname, std::forward<Args>( args )... ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
lua_class( std::string name, Args&&... args ) : lua_class( name, constructors<>(), std::forward<Args>( args )... ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args, typename... CArgs>
|
|
||||||
lua_class( std::string name, constructors<CArgs...> c, Args&&... args ) : luaname( std::move( name ) ) {
|
|
||||||
functionnames.reserve( sizeof...( args ) );
|
|
||||||
functiontable.reserve( sizeof...( args ) );
|
|
||||||
metatable.reserve( sizeof...( args ) );
|
|
||||||
build_function_tables( std::forward<Args>( args )... );
|
|
||||||
functiontable.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const std::string lua_class<T>::classname = detail::demangle( typeid( T ) );
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const std::string lua_class<T>::meta = std::string( "sol.stateful." ).append( classname );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct f {
|
|
||||||
int x;
|
|
||||||
f( ) : x( 1 ) {
|
|
||||||
}
|
|
||||||
f( int x ) : x( x ) {
|
|
||||||
}
|
|
||||||
int add( int y ) {
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main( ) {
|
|
||||||
sol::state s;
|
|
||||||
f x( 20 );
|
|
||||||
|
|
||||||
sol::lua_class<f> lc{ };
|
|
||||||
std::cout << lc.classname << std::endl;
|
|
||||||
std::cout << lc.meta << std::endl;
|
|
||||||
|
|
||||||
s.set_function( "add", &f::add, f(10) );
|
|
||||||
s.script( "t = add(20)" );
|
|
||||||
std::cout << s.get<int>( "t" );
|
|
||||||
}
|
|
|
@ -32,27 +32,27 @@ namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
std::string demangle(const std::type_info& id) {
|
std::string demangle(const std::type_info& id) {
|
||||||
/*std::string realname(2048, '\0');
|
/*std::string realname(2048, '\0');
|
||||||
DWORD result = UnDecorateSymbolName(id.raw_name(), &realname[0],
|
DWORD result = UnDecorateSymbolName(id.raw_name(), &realname[0],
|
||||||
static_cast<DWORD>(realname.size()), UNDNAME_NAME_ONLY | UNDNAME_32_BIT_DECODE);
|
static_cast<DWORD>(realname.size()), UNDNAME_NAME_ONLY | UNDNAME_32_BIT_DECODE);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
return "";
|
return "";
|
||||||
realname.resize(result);
|
realname.resize(result);
|
||||||
*/
|
*/
|
||||||
const static std::string removals[ 2 ] = {
|
const static std::string removals[ 2 ] = {
|
||||||
"struct ",
|
"struct ",
|
||||||
"class "
|
"class "
|
||||||
};
|
};
|
||||||
std::string realname = id.name( );
|
std::string realname = id.name();
|
||||||
for ( std::size_t r = 0; r < 2; ++r ) {
|
for (std::size_t r = 0; r < 2; ++r) {
|
||||||
auto found = realname.find( removals[ r ] );
|
auto found = realname.find(removals[ r ]);
|
||||||
if ( found == std::string::npos )
|
if (found == std::string::npos)
|
||||||
continue;
|
continue;
|
||||||
realname.erase( found, removals[r].size() );
|
realname.erase(found, removals[r].size());
|
||||||
}
|
}
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif __GNUC__ || __clang__
|
#elif __GNUC__ || __clang__
|
||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
|
@ -60,13 +60,13 @@ namespace detail {
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
std::string demangle(const std::type_info& id) {
|
std::string demangle(const std::type_info& id) {
|
||||||
int status;
|
int status;
|
||||||
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
|
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
|
||||||
std::string realname = unmangled;
|
std::string realname = unmangled;
|
||||||
free(unmangled);
|
free(unmangled);
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
namespace sol {
|
namespace sol {
|
||||||
|
|
|
@ -26,37 +26,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
|
||||||
template<typename T, std::size_t N>
|
|
||||||
void get_upvalue_ptr(lua_State* L, T*& data, std::size_t datasize, std::array<void*, N> voiddata, int& upvalue) {
|
|
||||||
for (std::size_t i = 0, d = 0; d < datasize; ++i, d += sizeof(void*)) {
|
|
||||||
voiddata[i] = lua_touserdata(L, lua_upvalueindex(upvalue++));
|
|
||||||
}
|
|
||||||
data = reinterpret_cast<T*>(static_cast<void*>(voiddata.data()));
|
|
||||||
}
|
|
||||||
template<typename T, std::size_t N>
|
|
||||||
void get_upvalue_ptr(lua_State* L, T*& data, std::array<void*, N> voiddata, int& upvalue) {
|
|
||||||
get_upvalue_ptr(L, data, sizeof(T), voiddata, upvalue);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
void get_upvalue_ptr(lua_State* L, T*& data, int& upvalue) {
|
|
||||||
const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*);
|
|
||||||
typedef std::array<void*, data_t_count> data_t;
|
|
||||||
data_t voiddata{{}};
|
|
||||||
return get_upvalue_ptr(L, data, voiddata, upvalue);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
void get_upvalue(lua_State* L, T& data, int& upvalue) {
|
|
||||||
const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*);
|
|
||||||
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] = lua_touserdata(L, lua_upvalueindex(upvalue++));
|
|
||||||
}
|
|
||||||
data = *reinterpret_cast<T*>(static_cast<void*>(voiddata.data()));
|
|
||||||
}
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename TFx>
|
||||||
struct static_lua_func {
|
struct static_lua_func {
|
||||||
|
@ -83,10 +52,9 @@ struct static_lua_func {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call(lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
int upvalue = 1;
|
auto udata = stack::get_user<fx_t*>(L);
|
||||||
fx_t* fx;
|
fx_t* fx = udata.first;
|
||||||
detail::get_upvalue(L, fx, upvalue);
|
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), fx, L);
|
||||||
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), fx, L);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,19 +90,11 @@ struct static_object_lua_func {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call(lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
const static std::size_t data_t_count = (sizeof(fx_t)+(sizeof(void*)-1)) / sizeof(void*);
|
auto memberdata = stack::get_user<fx_t>(L, 1);
|
||||||
typedef std::array<void*, data_t_count> data_t;
|
auto objdata = stack::get_user<T*>(L, memberdata.second);
|
||||||
int upvalue = 1;
|
fx_t& memfx = memberdata.first;
|
||||||
data_t data = {{}};
|
T& obj = *objdata.first;
|
||||||
fx_t* fxptr;
|
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), obj, memfx, L);
|
||||||
for (std::size_t i = 0, d = 0; d < sizeof(fx_t*); ++i, d += sizeof(void*)) {
|
|
||||||
data[i] = lua_touserdata(L, lua_upvalueindex(upvalue++));
|
|
||||||
}
|
|
||||||
fxptr = reinterpret_cast<fx_t*>(static_cast<void*>(data.data()));
|
|
||||||
fx_t& mem_ptr = *fxptr;
|
|
||||||
void* objectdata = lua_touserdata(L, lua_upvalueindex(upvalue++));
|
|
||||||
T& obj = *static_cast<T*>(objectdata);
|
|
||||||
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), obj, mem_ptr, L);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +105,7 @@ struct static_object_lua_func {
|
||||||
|
|
||||||
struct lua_func {
|
struct lua_func {
|
||||||
static int call(lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
void** pinheritancedata = static_cast<void**>(lua_touserdata(L, lua_upvalueindex(1)));
|
void** pinheritancedata = static_cast<void**>(stack::get<lightuserdata_t>(L, 1).value);
|
||||||
void* inheritancedata = *pinheritancedata;
|
void* inheritancedata = *pinheritancedata;
|
||||||
if (inheritancedata == nullptr)
|
if (inheritancedata == nullptr)
|
||||||
throw sol_error("call from Lua to C++ function has null data");
|
throw sol_error("call from Lua to C++ function has null data");
|
||||||
|
@ -156,7 +116,7 @@ struct lua_func {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gc(lua_State* L) {
|
static int gc(lua_State* L) {
|
||||||
void** puserdata = static_cast<void**>(lua_touserdata(L, 1));
|
void** puserdata = static_cast<void**>(stack::get<userdata_t>(L, 1).value);
|
||||||
void* userdata = *puserdata;
|
void* userdata = *puserdata;
|
||||||
lua_func* ptr = static_cast<lua_func*>(userdata);
|
lua_func* ptr = static_cast<lua_func*>(userdata);
|
||||||
std::default_delete<lua_func> dx{};
|
std::default_delete<lua_func> dx{};
|
||||||
|
@ -175,15 +135,11 @@ template<typename TFx>
|
||||||
struct functor_lua_func : public lua_func {
|
struct functor_lua_func : public lua_func {
|
||||||
typedef decltype(&TFx::operator()) fx_t;
|
typedef decltype(&TFx::operator()) fx_t;
|
||||||
typedef function_traits<fx_t> fx_traits;
|
typedef function_traits<fx_t> fx_traits;
|
||||||
fx_t fx;
|
TFx fx;
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename... FxArgs>
|
||||||
functor_lua_func(FxArgs&&... fxargs): fx(std::forward<FxArgs>(fxargs)...) {}
|
functor_lua_func(FxArgs&&... fxargs): fx(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||||
stack::pop_call(L, fx, t);
|
stack::pop_call(L, fx, t);
|
||||||
|
@ -202,6 +158,10 @@ struct functor_lua_func : public lua_func {
|
||||||
stack::push(L, r);
|
stack::push(L, r);
|
||||||
return sizeof...(Ret);
|
return sizeof...(Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual int operator()(lua_State* L) override {
|
||||||
|
return (*this)(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), L);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TFx, typename T = TFx, bool is_member_pointer = std::is_member_function_pointer<TFx>::value>
|
template<typename TFx, typename T = TFx, bool is_member_pointer = std::is_member_function_pointer<TFx>::value>
|
||||||
|
@ -286,21 +246,21 @@ struct class_lua_func : public lua_func {
|
||||||
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t;
|
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t;
|
||||||
typedef function_traits<fx_t> fx_traits;
|
typedef function_traits<fx_t> fx_traits;
|
||||||
struct functor {
|
struct functor {
|
||||||
T& member;
|
T* item;
|
||||||
fx_t invocation;
|
fx_t invocation;
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename... FxArgs>
|
||||||
functor(FxArgs&&... fxargs): member(*static_cast<T*>(nullptr)), invocation(std::forward<FxArgs>(fxargs)...) {}
|
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||||
|
|
||||||
void pre_call( lua_State* L ) {
|
void pre_call(lua_State* L) {
|
||||||
void* userdata = lua_touserdata( L, 0 );
|
void* userdata = lua_touserdata(L, 0);
|
||||||
T* item = static_cast<T*>( userdata );
|
item = static_cast<T*>(userdata);
|
||||||
member = *item;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
typename fx_traits::return_type operator()(Args&&... args) {
|
typename fx_traits::return_type operator()(Args&&... args) {
|
||||||
return (member.*invocation)(std::forward<Args>(args)...);
|
T& member = *item;
|
||||||
|
return (member.*invocation)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
} fx;
|
} fx;
|
||||||
|
|
||||||
|
@ -309,8 +269,7 @@ struct class_lua_func : public lua_func {
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||||
fx.pre_call(L);
|
stack::pop_call(L, fx, t);
|
||||||
stack::pop_call(L, fx, t);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,13 +281,13 @@ struct class_lua_func : public lua_func {
|
||||||
template<typename... Ret, typename... Args>
|
template<typename... Ret, typename... Args>
|
||||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||||
typedef typename multi_return<Ret...>::type return_type;
|
typedef typename multi_return<Ret...>::type return_type;
|
||||||
fx.pre_call(L);
|
return_type r = stack::pop_call(L, fx, t);
|
||||||
return_type r = stack::pop_call(L, fx, t);
|
|
||||||
stack::push(L, std::move(r));
|
stack::push(L, std::move(r));
|
||||||
return sizeof...(Ret);
|
return sizeof...(Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int operator()(lua_State* L) override {
|
virtual int operator()(lua_State* L) override {
|
||||||
|
fx.pre_call(L);
|
||||||
return (*this)(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), L);
|
return (*this)(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,11 +46,14 @@ public:
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, ref);
|
luaL_unref(L, LUA_REGISTRYINDEX, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void push() const noexcept {
|
void push() const noexcept {
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pop() const noexcept {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
reference(reference&& o) noexcept {
|
reference(reference&& o) noexcept {
|
||||||
L = o.L;
|
L = o.L;
|
||||||
ref = o.ref;
|
ref = o.ref;
|
||||||
|
|
|
@ -112,6 +112,16 @@ inline bool get<bool>(lua_State* L, int index) {
|
||||||
return lua_toboolean(L, index) != 0;
|
return lua_toboolean(L, index) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline lightuserdata_t get<lightuserdata_t>(lua_State* L, int index) {
|
||||||
|
return {lua_touserdata(L, lua_upvalueindex(index))};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline userdata_t get<userdata_t>(lua_State* L, int index) {
|
||||||
|
return {lua_touserdata(L, index)};
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline std::string get<std::string>(lua_State* L, int index) {
|
inline std::string get<std::string>(lua_State* L, int index) {
|
||||||
std::string::size_type len;
|
std::string::size_type len;
|
||||||
|
@ -124,6 +134,17 @@ inline const char* get<const char*>(lua_State* L, int index) {
|
||||||
return lua_tostring(L, index);
|
return lua_tostring(L, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline std::pair<T, int> get_user(lua_State* L, int index = 1) {
|
||||||
|
const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*);
|
||||||
|
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 ] = stack::get<lightuserdata_t>(L, index++);
|
||||||
|
}
|
||||||
|
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T pop(lua_State* L) {
|
inline T pop(lua_State* L) {
|
||||||
auto r = get<T>(L);
|
auto r = get<T>(L);
|
||||||
|
|
|
@ -144,9 +144,15 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename TFx, typename TM>
|
template<typename T, typename TFx, typename TObj>
|
||||||
state& set_function(T&& key, TFx&& fx, TM& mem) {
|
state& set_function(T&& key, TFx&& fx, TObj&& obj) {
|
||||||
global.set_function(std::forward<T>(key), std::forward<TFx>(fx), mem);
|
global.set_function(std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
state& set_class(userdata<T>& user) {
|
||||||
|
global.set_class(user);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
#include "proxy.hpp"
|
#include "proxy.hpp"
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
#include "lua_function.hpp"
|
#include "lua_function.hpp"
|
||||||
#include <array>
|
#include "userdata.hpp"
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -114,6 +113,46 @@ public:
|
||||||
std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
table& set_class(userdata<T>& user) {
|
||||||
|
push();
|
||||||
|
|
||||||
|
lua_createtable(state(), 0, 0);
|
||||||
|
int classid = lua_gettop(state());
|
||||||
|
|
||||||
|
// Register metatable for user data in registry
|
||||||
|
// using the metaname key generated from the demangled name
|
||||||
|
luaL_newmetatable(state(), user.meta.c_str());
|
||||||
|
int metaid = lua_gettop(state());
|
||||||
|
// Meta functions: have no light up values
|
||||||
|
luaL_setfuncs(state(), user.metatable.data(), 0);
|
||||||
|
|
||||||
|
// Regular functions: each one references an upvalue at its own index,
|
||||||
|
// resulting in [function count] upvalues
|
||||||
|
//luaL_newlib(L, functiontable.data());
|
||||||
|
// the newlib macro doesn't have a form for when you need upvalues:
|
||||||
|
// we duplicate the work below
|
||||||
|
lua_createtable(state(), 0, user.functiontable.size() - 1);
|
||||||
|
for (std::size_t upvalues = 0; upvalues < user.functions.size(); ++upvalues) {
|
||||||
|
stack::push(state(), static_cast<void*>(user.functions[ upvalues ].get()));
|
||||||
|
}
|
||||||
|
luaL_setfuncs(state(), user.functiontable.data(), static_cast<uint32_t>(user.functions.size()));
|
||||||
|
lua_setfield(state(), metaid, "__index");
|
||||||
|
|
||||||
|
// Meta functions: no upvalues
|
||||||
|
lua_createtable(state(), 0, user.metatable.size() - 1);
|
||||||
|
luaL_setfuncs(state(), user.metatable.data(), 0); // 0, for no upvalues
|
||||||
|
lua_setfield(state(), metaid, "__metatable");
|
||||||
|
|
||||||
|
lua_setmetatable(state(), classid);
|
||||||
|
|
||||||
|
lua_setglobal(state(), user.luaname.c_str());
|
||||||
|
|
||||||
|
pop();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
push();
|
push();
|
||||||
return lua_rawlen(state(), -1);
|
return lua_rawlen(state(), -1);
|
||||||
|
@ -194,7 +233,7 @@ private:
|
||||||
stack::push(state(), userobjdata);
|
stack::push(state(), userobjdata);
|
||||||
luaL_setfuncs(state(), funcreg, upvalues + 1);
|
luaL_setfuncs(state(), funcreg, upvalues + 1);
|
||||||
|
|
||||||
lua_pop(state(), 1);
|
pop();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,11 +249,10 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
push();
|
push();
|
||||||
|
|
||||||
int upvalues = stack::push_user(state(), target);
|
int upvalues = stack::push_user(state(), target);
|
||||||
luaL_setfuncs(state(), funcreg, upvalues);
|
luaL_setfuncs(state(), funcreg, upvalues);
|
||||||
|
pop();
|
||||||
|
|
||||||
lua_pop(state(), 1);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +281,7 @@ private:
|
||||||
push();
|
push();
|
||||||
stack::push_user(state(), userdata, metatablename);
|
stack::push_user(state(), userdata, metatablename);
|
||||||
luaL_setfuncs(state(), funcreg, 1);
|
luaL_setfuncs(state(), funcreg, 1);
|
||||||
lua_pop(state(), 1);
|
pop();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,7 +58,7 @@ using Bool = std::integral_constant<bool, B>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
|
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
|
||||||
struct is_function_impl : std::is_function<typename std::remove_pointer<T>::type> { };
|
struct is_function_impl : std::is_function<typename std::remove_pointer<T>::type> {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_function_impl<T, true> {
|
struct is_function_impl<T, true> {
|
||||||
|
@ -66,7 +66,7 @@ struct is_function_impl<T, true> {
|
||||||
using no = struct { char s[2]; };
|
using no = struct { char s[2]; };
|
||||||
|
|
||||||
struct F { void operator()(); };
|
struct F { void operator()(); };
|
||||||
struct Derived : T, F { };
|
struct Derived : T, F {};
|
||||||
template<typename U, U> struct Check;
|
template<typename U, U> struct Check;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
|
@ -80,7 +80,7 @@ struct is_function_impl<T, true> {
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Function : Bool<detail::is_function_impl<T>::value> { };
|
struct Function : Bool<detail::is_function_impl<T>::value> {};
|
||||||
|
|
||||||
template<typename TFuncSignature>
|
template<typename TFuncSignature>
|
||||||
struct function_traits;
|
struct function_traits;
|
||||||
|
|
|
@ -73,6 +73,10 @@ struct tuple_types : types<Args...>, std::false_type {};
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
struct tuple_types<std::tuple<Args...>> : types<Args...>, std::true_type {};
|
struct tuple_types<std::tuple<Args...>> : types<Args...>, std::true_type {};
|
||||||
|
|
||||||
|
template <typename... Tn>
|
||||||
|
struct constructors {};
|
||||||
|
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_TUPLE_HPP
|
#endif // SOL_TUPLE_HPP
|
|
@ -31,6 +31,17 @@ struct nil_t {};
|
||||||
const nil_t nil {};
|
const nil_t nil {};
|
||||||
struct void_type {};
|
struct void_type {};
|
||||||
const void_type Void {};
|
const void_type Void {};
|
||||||
|
struct lightuserdata_t {
|
||||||
|
void* value;
|
||||||
|
lightuserdata_t(void* data) : value(data) {}
|
||||||
|
operator void* () const { return value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct userdata_t {
|
||||||
|
void* value;
|
||||||
|
userdata_t(void* data) : value(data) {}
|
||||||
|
operator void* () const { return value; }
|
||||||
|
};
|
||||||
|
|
||||||
enum class type : int {
|
enum class type : int {
|
||||||
none = LUA_TNONE,
|
none = LUA_TNONE,
|
||||||
|
@ -58,6 +69,8 @@ inline void type_assert(lua_State* L, int index, type expected) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class userdata;
|
||||||
class table;
|
class table;
|
||||||
class function;
|
class function;
|
||||||
class object;
|
class object;
|
||||||
|
@ -114,6 +127,16 @@ inline type type_of<bool>() {
|
||||||
return type::boolean;
|
return type::boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline type type_of<lightuserdata_t>() {
|
||||||
|
return type::lightuserdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline type type_of<userdata_t>() {
|
||||||
|
return type::userdata;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator==(nil_t, nil_t) { return true; }
|
inline bool operator==(nil_t, nil_t) { return true; }
|
||||||
inline bool operator!=(nil_t, nil_t) { return false; }
|
inline bool operator!=(nil_t, nil_t) { return false; }
|
||||||
} // sol
|
} // sol
|
||||||
|
|
161
sol/userdata.hpp
Normal file
161
sol/userdata.hpp
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
// The MIT License (MIT)
|
||||||
|
|
||||||
|
// Copyright (c) 2013 Danny Y., Rapptz
|
||||||
|
|
||||||
|
// 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_USERDATA_HPP
|
||||||
|
#define SOL_USERDATA_HPP
|
||||||
|
|
||||||
|
#include <sol/state.hpp>
|
||||||
|
#include <sol/lua_function.hpp>
|
||||||
|
#include <sol/demangle.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sol {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class userdata {
|
||||||
|
private:
|
||||||
|
friend table;
|
||||||
|
static const std::string classname;
|
||||||
|
static const std::string meta;
|
||||||
|
|
||||||
|
std::string luaname;
|
||||||
|
std::vector<std::string> functionnames;
|
||||||
|
std::vector<std::unique_ptr<lua_func>> functions;
|
||||||
|
std::vector<luaL_Reg> functiontable;
|
||||||
|
std::vector<luaL_Reg> metatable;
|
||||||
|
|
||||||
|
struct constructor {
|
||||||
|
static int construct(lua_State* L) {
|
||||||
|
// First argument is now a table that represent the class to instantiate
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
|
||||||
|
lua_createtable(L, 0, 0); // Create table to represent instance
|
||||||
|
|
||||||
|
// Set first argument of new to metatable of instance
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
|
||||||
|
// Do function lookups in metatable
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_setfield(L, 1, "__index");
|
||||||
|
|
||||||
|
void* userdata = lua_newuserdata(L, sizeof(T));
|
||||||
|
T* obj = static_cast<T*>(userdata);
|
||||||
|
std::allocator<T> alloc{};
|
||||||
|
alloc.construct(obj);
|
||||||
|
|
||||||
|
luaL_getmetatable(L, meta.c_str());
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
lua_setfield(L, -2, "__self");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::size_t n>
|
||||||
|
struct destructor {
|
||||||
|
static int destruct(lua_State* L) {
|
||||||
|
for (std::size_t i = 0; i < n; ++i) {
|
||||||
|
lightuserdata_t luserdata = stack::get<lightuserdata_t>(L, i);
|
||||||
|
}
|
||||||
|
userdata_t userdata = stack::get<userdata_t>(L, 0);
|
||||||
|
T* obj = static_cast<T*>(userdata.value);
|
||||||
|
std::allocator<T> alloc{};
|
||||||
|
alloc.destroy(obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::size_t i>
|
||||||
|
struct class_func {
|
||||||
|
static int call(lua_State* L) {
|
||||||
|
// Zero-based template parameter, but upvalues start at 1
|
||||||
|
void* inheritancedata = stack::get<lightuserdata_t>(L, i + 1);
|
||||||
|
if (inheritancedata == nullptr)
|
||||||
|
throw sol_error("call from Lua to C++ function has null data");
|
||||||
|
lua_func* pfx = static_cast<lua_func*>(inheritancedata);
|
||||||
|
lua_func& fx = *pfx;
|
||||||
|
int r = fx(L);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::size_t n>
|
||||||
|
void build_function_tables() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t n, typename... Args, typename Ret, typename... MArgs>
|
||||||
|
void build_function_tables(Ret(T::* func)(MArgs...), std::string name, Args&&... args) {
|
||||||
|
typedef typename std::decay<decltype(func)>::type fx_t;
|
||||||
|
functionnames.push_back(std::move(name));
|
||||||
|
functions.emplace_back(std::make_unique<class_lua_func<fx_t, T>>(std::move(func)));
|
||||||
|
functiontable.push_back({ functionnames.back().c_str(), &class_func<n>::call });
|
||||||
|
build_function_tables<n + 1>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
userdata(Args&&... args) : userdata(classname, std::forward<Args>(args)...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
userdata(std::string name, Args&&... args) : userdata(name, constructors<>(), std::forward<Args>(args)...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename... CArgs>
|
||||||
|
userdata(constructors<CArgs...> c, Args&&... args) : userdata(classname, std::move(c), std::forward<Args>(args)...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename... CArgs>
|
||||||
|
userdata(std::string name, constructors<CArgs...> c, Args&&... args) : luaname(std::move(name)) {
|
||||||
|
functionnames.reserve(sizeof...(args));
|
||||||
|
functiontable.reserve(sizeof...(args));
|
||||||
|
functions.reserve(sizeof...(args));
|
||||||
|
metatable.reserve(sizeof...(args));
|
||||||
|
build_function_tables<0>(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
functionnames.push_back("new");
|
||||||
|
functiontable.push_back({ functionnames.back().c_str(), &constructor::construct });
|
||||||
|
functiontable.push_back({ nullptr, nullptr });
|
||||||
|
|
||||||
|
metatable.push_back({ "__gc", &destructor<sizeof...(Args) / 2>::destruct });
|
||||||
|
metatable.push_back({ nullptr, nullptr });
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_into(const table& s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const std::string userdata<T>::classname = detail::demangle(typeid(T));
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const std::string userdata<T>::meta = std::string("sol.stateful.").append(classname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif SOL_USERDATA_HPP
|
48
tests.cpp
48
tests.cpp
|
@ -16,6 +16,26 @@ struct object {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fuser {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
fuser( ) : x( 0 ) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fuser( int x ) : x( x ) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int add( int y ) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add2( int y ) {
|
||||||
|
return x + y + 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int plop_xyz(int x, int y, std::string z) {
|
int plop_xyz(int x, int y, std::string z) {
|
||||||
std::cout << x << " " << y << " " << z << std::endl;
|
std::cout << x << " " << y << " " << z << std::endl;
|
||||||
return 11;
|
return 11;
|
||||||
|
@ -324,3 +344,31 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
|
||||||
|
|
||||||
REQUIRE_NOTHROW(assert1(lua.global_table()));
|
REQUIRE_NOTHROW(assert1(lua.global_table()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "tables/userdata", "Show that we can create classes from userdata and use them" ) {
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
|
||||||
|
sol::userdata<fuser> lc{ &fuser::add, "add", &fuser::add2, "add2" };
|
||||||
|
lua.set_class( lc );
|
||||||
|
|
||||||
|
lua.script( "a = fuser:new()\n"
|
||||||
|
"b = a:add(1)\n"
|
||||||
|
"c = a:add2(1)\n"
|
||||||
|
"\n" );
|
||||||
|
|
||||||
|
sol::object a = lua.get<sol::object>( "a" );
|
||||||
|
sol::object b = lua.get<sol::object>( "b" );
|
||||||
|
sol::object c = lua.get<sol::object>( "c" );
|
||||||
|
REQUIRE( ( a.is<sol::table>( ) ) );
|
||||||
|
auto atype = a.get_type( );
|
||||||
|
auto btype = b.get_type( );
|
||||||
|
auto ctype = c.get_type( );
|
||||||
|
REQUIRE( ( atype == sol::type::table ) );
|
||||||
|
REQUIRE( ( btype == sol::type::number ) );
|
||||||
|
REQUIRE( ( ctype == sol::type::number ) );
|
||||||
|
int bresult = b.as<int>( );
|
||||||
|
int cresult = c.as<int>( );
|
||||||
|
REQUIRE( bresult == 1 );
|
||||||
|
REQUIRE( cresult == 3 );
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user