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" );
|
||||
}
|
|
@ -44,12 +44,12 @@ namespace detail {
|
|||
"struct ",
|
||||
"class "
|
||||
};
|
||||
std::string realname = id.name( );
|
||||
for ( std::size_t r = 0; r < 2; ++r ) {
|
||||
auto found = realname.find( removals[ r ] );
|
||||
if ( found == std::string::npos )
|
||||
std::string realname = id.name();
|
||||
for (std::size_t r = 0; r < 2; ++r) {
|
||||
auto found = realname.find(removals[ r ]);
|
||||
if (found == std::string::npos)
|
||||
continue;
|
||||
realname.erase( found, removals[r].size() );
|
||||
realname.erase(found, removals[r].size());
|
||||
}
|
||||
return realname;
|
||||
}
|
||||
|
|
|
@ -26,37 +26,6 @@
|
|||
#include <memory>
|
||||
|
||||
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>
|
||||
struct static_lua_func {
|
||||
|
@ -83,9 +52,8 @@ struct static_lua_func {
|
|||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
int upvalue = 1;
|
||||
fx_t* fx;
|
||||
detail::get_upvalue(L, fx, upvalue);
|
||||
auto udata = stack::get_user<fx_t*>(L);
|
||||
fx_t* fx = udata.first;
|
||||
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), fx, L);
|
||||
return r;
|
||||
}
|
||||
|
@ -122,19 +90,11 @@ struct static_object_lua_func {
|
|||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
const static std::size_t data_t_count = (sizeof(fx_t)+(sizeof(void*)-1)) / sizeof(void*);
|
||||
typedef std::array<void*, data_t_count> data_t;
|
||||
int upvalue = 1;
|
||||
data_t data = {{}};
|
||||
fx_t* fxptr;
|
||||
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);
|
||||
auto memberdata = stack::get_user<fx_t>(L, 1);
|
||||
auto objdata = stack::get_user<T*>(L, memberdata.second);
|
||||
fx_t& memfx = memberdata.first;
|
||||
T& obj = *objdata.first;
|
||||
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), obj, memfx, L);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -145,7 +105,7 @@ struct static_object_lua_func {
|
|||
|
||||
struct lua_func {
|
||||
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;
|
||||
if (inheritancedata == nullptr)
|
||||
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) {
|
||||
void** puserdata = static_cast<void**>(lua_touserdata(L, 1));
|
||||
void** puserdata = static_cast<void**>(stack::get<userdata_t>(L, 1).value);
|
||||
void* userdata = *puserdata;
|
||||
lua_func* ptr = static_cast<lua_func*>(userdata);
|
||||
std::default_delete<lua_func> dx{};
|
||||
|
@ -175,15 +135,11 @@ template<typename TFx>
|
|||
struct functor_lua_func : public lua_func {
|
||||
typedef decltype(&TFx::operator()) fx_t;
|
||||
typedef function_traits<fx_t> fx_traits;
|
||||
fx_t fx;
|
||||
TFx fx;
|
||||
|
||||
template<typename... 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>
|
||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||
stack::pop_call(L, fx, t);
|
||||
|
@ -202,6 +158,10 @@ struct functor_lua_func : public lua_func {
|
|||
stack::push(L, r);
|
||||
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>
|
||||
|
@ -286,20 +246,20 @@ struct class_lua_func : public lua_func {
|
|||
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t;
|
||||
typedef function_traits<fx_t> fx_traits;
|
||||
struct functor {
|
||||
T& member;
|
||||
T* item;
|
||||
fx_t invocation;
|
||||
|
||||
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* userdata = lua_touserdata( L, 0 );
|
||||
T* item = static_cast<T*>( userdata );
|
||||
member = *item;
|
||||
void pre_call(lua_State* L) {
|
||||
void* userdata = lua_touserdata(L, 0);
|
||||
item = static_cast<T*>(userdata);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
typename fx_traits::return_type operator()(Args&&... args) {
|
||||
T& member = *item;
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
} fx;
|
||||
|
@ -309,7 +269,6 @@ struct class_lua_func : public lua_func {
|
|||
|
||||
template<typename... Args>
|
||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||
fx.pre_call(L);
|
||||
stack::pop_call(L, fx, t);
|
||||
return 0;
|
||||
}
|
||||
|
@ -322,13 +281,13 @@ struct class_lua_func : public lua_func {
|
|||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||
typedef typename multi_return<Ret...>::type return_type;
|
||||
fx.pre_call(L);
|
||||
return_type r = stack::pop_call(L, fx, t);
|
||||
stack::push(L, std::move(r));
|
||||
return sizeof...(Ret);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -46,11 +46,14 @@ public:
|
|||
luaL_unref(L, LUA_REGISTRYINDEX, ref);
|
||||
}
|
||||
|
||||
|
||||
void push() const noexcept {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
}
|
||||
|
||||
void pop() const noexcept {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
reference(reference&& o) noexcept {
|
||||
L = o.L;
|
||||
ref = o.ref;
|
||||
|
|
|
@ -112,6 +112,16 @@ inline bool get<bool>(lua_State* L, int index) {
|
|||
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<>
|
||||
inline std::string get<std::string>(lua_State* L, int index) {
|
||||
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);
|
||||
}
|
||||
|
||||
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>
|
||||
inline T pop(lua_State* L) {
|
||||
auto r = get<T>(L);
|
||||
|
|
|
@ -144,9 +144,15 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename TFx, typename TM>
|
||||
state& set_function(T&& key, TFx&& fx, TM& mem) {
|
||||
global.set_function(std::forward<T>(key), std::forward<TFx>(fx), mem);
|
||||
template<typename T, typename TFx, typename TObj>
|
||||
state& set_function(T&& key, TFx&& fx, TObj&& obj) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
#include "proxy.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "lua_function.hpp"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include "userdata.hpp"
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
|
@ -114,6 +113,46 @@ public:
|
|||
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 {
|
||||
push();
|
||||
return lua_rawlen(state(), -1);
|
||||
|
@ -194,7 +233,7 @@ private:
|
|||
stack::push(state(), userobjdata);
|
||||
luaL_setfuncs(state(), funcreg, upvalues + 1);
|
||||
|
||||
lua_pop(state(), 1);
|
||||
pop();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -210,11 +249,10 @@ private:
|
|||
};
|
||||
|
||||
push();
|
||||
|
||||
int upvalues = stack::push_user(state(), target);
|
||||
luaL_setfuncs(state(), funcreg, upvalues);
|
||||
pop();
|
||||
|
||||
lua_pop(state(), 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -243,7 +281,7 @@ private:
|
|||
push();
|
||||
stack::push_user(state(), userdata, metatablename);
|
||||
luaL_setfuncs(state(), funcreg, 1);
|
||||
lua_pop(state(), 1);
|
||||
pop();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -58,7 +58,7 @@ using Bool = std::integral_constant<bool, B>;
|
|||
|
||||
namespace detail {
|
||||
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>
|
||||
struct is_function_impl<T, true> {
|
||||
|
@ -66,7 +66,7 @@ struct is_function_impl<T, true> {
|
|||
using no = struct { char s[2]; };
|
||||
|
||||
struct F { void operator()(); };
|
||||
struct Derived : T, F { };
|
||||
struct Derived : T, F {};
|
||||
template<typename U, U> struct Check;
|
||||
|
||||
template<typename V>
|
||||
|
@ -80,7 +80,7 @@ struct is_function_impl<T, true> {
|
|||
} // detail
|
||||
|
||||
template<typename T>
|
||||
struct Function : Bool<detail::is_function_impl<T>::value> { };
|
||||
struct Function : Bool<detail::is_function_impl<T>::value> {};
|
||||
|
||||
template<typename TFuncSignature>
|
||||
struct function_traits;
|
||||
|
|
|
@ -73,6 +73,10 @@ struct tuple_types : types<Args...>, std::false_type {};
|
|||
|
||||
template<typename... Args>
|
||||
struct tuple_types<std::tuple<Args...>> : types<Args...>, std::true_type {};
|
||||
|
||||
template <typename... Tn>
|
||||
struct constructors {};
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_TUPLE_HPP
|
|
@ -31,6 +31,17 @@ struct nil_t {};
|
|||
const nil_t nil {};
|
||||
struct void_type {};
|
||||
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 {
|
||||
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 function;
|
||||
class object;
|
||||
|
@ -114,6 +127,16 @@ inline type type_of<bool>() {
|
|||
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 false; }
|
||||
} // 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) {
|
||||
std::cout << x << " " << y << " " << z << std::endl;
|
||||
return 11;
|
||||
|
@ -324,3 +344,31 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
|
|||
|
||||
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