mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Class binding now works with multiple functions
Refactoring on function_types.hpp performed to slim down some of the calls: could use more refactoring Drastically simplified userdata's binding capabilities: constructor supports both `:` and `.` syntax (but member functions DO NOT). All tests are passing
This commit is contained in:
parent
4d6d39be88
commit
0088002abf
|
@ -35,19 +35,19 @@ namespace detail {
|
|||
std::string demangle(const std::type_info& id) {
|
||||
const static std::array<std::string, 2> removals = { "struct ", "class " };
|
||||
const static std::array<std::string, 2> replacements = { "::", "_" };
|
||||
std::string realname = id.name( );
|
||||
std::string realname = id.name();
|
||||
for(std::size_t r = 0; r < removals.size(); ++r) {
|
||||
auto found = realname.find(removals[r]);
|
||||
while (found != std::string::npos) {
|
||||
while (found != std::string::npos) {
|
||||
realname.erase(found, removals[r].size());
|
||||
found = realname.find( removals[r] );
|
||||
}
|
||||
found = realname.find(removals[r]);
|
||||
}
|
||||
}
|
||||
for(std::size_t r = 0; r < replacements.size(); r+=2) {
|
||||
auto found = realname.find(replacements[r]);
|
||||
while (found != std::string::npos) {
|
||||
while (found != std::string::npos) {
|
||||
realname.replace(found, replacements[r].size(), replacements[r+1]);
|
||||
found = realname.find(replacements[r], found);
|
||||
found = realname.find(replacements[r], found);
|
||||
}
|
||||
}
|
||||
return realname;
|
||||
|
|
|
@ -104,26 +104,41 @@ struct static_member_function {
|
|||
};
|
||||
|
||||
struct base_function {
|
||||
static int call(lua_State* L) {
|
||||
void** pinheritancedata = static_cast<void**>(stack::get<lightuserdata_t>(L, 1).value);
|
||||
void* inheritancedata = *pinheritancedata;
|
||||
if (inheritancedata == nullptr) {
|
||||
static int base_call(lua_State* L, void* inheritancedata) {
|
||||
if (inheritancedata == nullptr)
|
||||
throw sol_error("call from Lua to C++ function has null data");
|
||||
}
|
||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||
base_function& fx = *pfx;
|
||||
int r = fx(L);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
void** puserdata = static_cast<void**>(stack::get<userdata_t>(L, 1).value);
|
||||
void* userdata = *puserdata;
|
||||
base_function* ptr = static_cast<base_function*>(userdata);
|
||||
static int base_gc(lua_State* L, void* udata) {
|
||||
if (udata == nullptr)
|
||||
throw sol_error("call from lua to C++ gc function with null data");
|
||||
base_function* ptr = static_cast<base_function*>(udata);
|
||||
std::default_delete<base_function> dx{};
|
||||
dx(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
void** pinheritancedata = static_cast<void**>(stack::get<lightuserdata_t>(L, 1).value);
|
||||
return base_call(L, *pinheritancedata);
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
void** pudata = static_cast<void**>(stack::get<userdata_t>(L, 1).value);
|
||||
return base_gc(L, *pudata);
|
||||
}
|
||||
|
||||
template<std::size_t i>
|
||||
struct userdata {
|
||||
static int call(lua_State* L) {
|
||||
// Zero-based template parameter, but upvalues start at 1
|
||||
return base_call(L, stack::get<lightuserdata_t>(L, i + 1));
|
||||
}
|
||||
};
|
||||
|
||||
virtual int operator()(lua_State*) {
|
||||
throw sol_error("failure to call specialized wrapped C++ function from Lua");
|
||||
|
@ -220,9 +235,11 @@ struct userdata_function : public base_function {
|
|||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
void pre_call(lua_State* L) {
|
||||
void* userdata = lua_touserdata(L, 0);
|
||||
item = static_cast<T*>(userdata);
|
||||
void prepare(lua_State* L) {
|
||||
void* udata = stack::get<userdata_t>(L, 1);
|
||||
if (udata == nullptr)
|
||||
throw sol_error("must use the syntax [object]:[function] to call member functions bound to C++");
|
||||
item = static_cast<T*>(udata);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
|
@ -255,7 +272,7 @@ struct userdata_function : public base_function {
|
|||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
fx.pre_call(L);
|
||||
fx.prepare(L);
|
||||
return (*this)(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "function.hpp"
|
||||
|
||||
namespace sol {
|
||||
template <typename Table, typename Key>
|
||||
template<typename Table, typename Key>
|
||||
struct proxy {
|
||||
private:
|
||||
Table& tbl;
|
||||
|
@ -32,7 +32,7 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
proxy(Table& table, T&& key) : tbl(table), key(std::forward<T>(key)) {
|
||||
|
||||
}
|
||||
|
@ -80,22 +80,22 @@ public:
|
|||
return get<std::string>();
|
||||
}
|
||||
|
||||
template <typename T = void>
|
||||
template<typename T = void>
|
||||
operator bool() const {
|
||||
return get<bool>();
|
||||
}
|
||||
|
||||
template <typename T = void>
|
||||
template<typename T = void>
|
||||
operator double() const {
|
||||
return get<double>();
|
||||
}
|
||||
|
||||
template <typename T = void>
|
||||
template<typename T = void>
|
||||
operator float() const {
|
||||
return get<float>();
|
||||
}
|
||||
|
||||
template <typename T = void>
|
||||
template<typename T = void>
|
||||
operator int() const {
|
||||
return get<int>();
|
||||
}
|
||||
|
@ -106,22 +106,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Table, typename Key, typename T>
|
||||
template<typename Table, typename Key, typename T>
|
||||
inline bool operator== (T&& left, const proxy<Table, Key>& right) {
|
||||
return left == right.template get<Decay<T>>();
|
||||
}
|
||||
|
||||
template <typename Table, typename Key, typename T>
|
||||
template<typename Table, typename Key, typename T>
|
||||
inline bool operator== (const proxy<Table, Key>& right, T&& left) {
|
||||
return right.template get<Decay<T>>() == left;
|
||||
}
|
||||
|
||||
template <typename Table, typename Key, typename T>
|
||||
template<typename Table, typename Key, typename T>
|
||||
inline bool operator!= (T&& left, const proxy<Table, Key>& right) {
|
||||
return right.template get<Decay<T>>() != left;
|
||||
}
|
||||
|
||||
template <typename Table, typename Key, typename T>
|
||||
template<typename Table, typename Key, typename T>
|
||||
inline bool operator!= (const proxy<Table, Key>& right, T&& left) {
|
||||
return right.template get<Decay<T>>() != left;
|
||||
}
|
||||
|
|
|
@ -134,7 +134,12 @@ inline const char* get<const char*>(lua_State* L, int index) {
|
|||
return lua_tostring(L, index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<>
|
||||
inline type get<type>(lua_State* L, int index) {
|
||||
return static_cast<type>(lua_type(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;
|
||||
|
@ -234,6 +239,15 @@ inline void push_tuple(lua_State* L, indices<I...>, T&& tuplen) {
|
|||
swallow {'\0', (sol::stack::push(L, std::get<I>(tuplen)), '\0')... };
|
||||
}
|
||||
|
||||
template<typename F, typename... Vs, typename... Args>
|
||||
inline auto ltr_get(lua_State*, int index, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
|
||||
return f(std::forward<Vs>(vs)...);
|
||||
}
|
||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||
inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||
return ltr_get(L, index + 1, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., get<Head>(L, index));
|
||||
}
|
||||
|
||||
template<typename F, typename... Vs, typename... Args>
|
||||
inline auto ltr_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
|
||||
return f(std::forward<Vs>(vs)...);
|
||||
|
@ -278,6 +292,11 @@ inline void push_reverse(lua_State* L, std::tuple<Args...>&& tuplen) {
|
|||
detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), std::move(tuplen));
|
||||
}
|
||||
|
||||
template<typename... Args, typename TFx>
|
||||
inline auto get_call(lua_State* L, int index, TFx&& fx, types<Args...> t) -> decltype(detail::ltr_get(L, index, std::forward<TFx>(fx), t, t)) {
|
||||
return detail::ltr_get(L, index, std::forward<TFx>(fx), t, t);
|
||||
}
|
||||
|
||||
template<typename... Args, typename TFx>
|
||||
inline auto pop_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(detail::ltr_pop(L, std::forward<TFx>(fx), t, t)) {
|
||||
return detail::ltr_pop(L, std::forward<TFx>(fx), t, t);
|
||||
|
@ -298,6 +317,27 @@ inline void push_args(lua_State* L, Arg&& arg, Args&&... args) {
|
|||
stack::push(L, std::forward<Arg>(arg));
|
||||
void(swallow{'\0', (stack::push(L, std::forward<Args>(args)), '\0')... });
|
||||
}
|
||||
|
||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
|
||||
if (get<type>(L, 1) == type::table) {
|
||||
if (luaL_newmetatable(L, meta.c_str()) == 0) {
|
||||
lua_settop(L, -2);
|
||||
return call_syntax::colon;
|
||||
}
|
||||
}
|
||||
return call_syntax::dot;
|
||||
}
|
||||
|
||||
inline std::string dump_types(lua_State* L) {
|
||||
std::string visual;
|
||||
std::size_t size = lua_gettop(L) + 1;
|
||||
for (std::size_t i = 1; i < size; ++i) {
|
||||
if (i != 1)
|
||||
visual += " | ";
|
||||
visual += type_name(L, stack::get<type>(L, i));
|
||||
}
|
||||
return visual;
|
||||
}
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -180,12 +180,12 @@ public:
|
|||
return reg;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
proxy<table, T> operator[](T&& key) {
|
||||
return global[std::forward<T>(key)];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
proxy<const table, T> operator[](T&& key) const {
|
||||
return global[std::forward<T>(key)];
|
||||
}
|
||||
|
|
|
@ -113,43 +113,19 @@ public:
|
|||
std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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_pushvalue(state(), -1);
|
||||
lua_setfield(state(), -1, "__index");
|
||||
|
||||
lua_setglobal(state(), user.luaname.c_str());
|
||||
|
||||
pop();
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -158,12 +134,12 @@ public:
|
|||
return lua_rawlen(state(), -1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
proxy<table, T> operator[](T&& key) {
|
||||
return proxy<table, T>(*this, std::forward<T>(key));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
proxy<const table, T> operator[](T&& key) const {
|
||||
return proxy<const table, T>(*this, std::forward<T>(key));
|
||||
}
|
||||
|
|
|
@ -74,9 +74,11 @@ 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>
|
||||
template<typename... Tn>
|
||||
struct constructors {};
|
||||
|
||||
const auto default_constructor = constructors<types<>>{};
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_TUPLE_HPP
|
|
@ -43,6 +43,11 @@ struct userdata_t {
|
|||
operator void* () const { return value; }
|
||||
};
|
||||
|
||||
enum class call_syntax {
|
||||
dot = 0,
|
||||
colon = 1
|
||||
};
|
||||
|
||||
enum class type : int {
|
||||
none = LUA_TNONE,
|
||||
nil = LUA_TNIL,
|
||||
|
@ -69,7 +74,11 @@ inline void type_assert(lua_State* L, int index, type expected) {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::string type_name(lua_State*L, type t) {
|
||||
return lua_typename(L, static_cast<int>(t));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class userdata;
|
||||
class table;
|
||||
class function;
|
||||
|
|
125
sol/userdata.hpp
125
sol/userdata.hpp
|
@ -35,7 +35,7 @@ inline std::unique_ptr<T> make_unique(Args&&... args) {
|
|||
}
|
||||
} // detail
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
class userdata {
|
||||
private:
|
||||
friend table;
|
||||
|
@ -46,142 +46,105 @@ private:
|
|||
std::vector<std::string> functionnames;
|
||||
std::vector<std::unique_ptr<base_function>> functions;
|
||||
std::vector<luaL_Reg> functiontable;
|
||||
std::vector<luaL_Reg> metatable;
|
||||
|
||||
template <typename... TTypes>
|
||||
template<typename... TTypes>
|
||||
struct constructor {
|
||||
template <typename... Args>
|
||||
static void do_constructor(lua_State* L, T* obj, int argcount, types<Args...> t) {
|
||||
auto fx = [&obj] ( Args&&... args ) -> void {
|
||||
template<typename... Args>
|
||||
static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int argcount, types<Args...>) {
|
||||
auto fx = [&obj] (Args&&... args) -> void {
|
||||
std::allocator<T> alloc{};
|
||||
alloc.construct(obj, std::forward<Args>(args)...);
|
||||
};
|
||||
stack::pop_call(L, fx, t);
|
||||
}
|
||||
stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>());
|
||||
}
|
||||
|
||||
static void match_constructor(lua_State* L, T* obj, int argcount) {
|
||||
if (argcount != 0)
|
||||
throw sol_error("No matching constructor for the arguments provided");
|
||||
static void match_constructor(lua_State* L, T* obj, call_syntax, int argcount) {
|
||||
throw sol_error("No matching constructor for the arguments provided");
|
||||
}
|
||||
|
||||
template<typename ...CArgs, typename... Args>
|
||||
static void match_constructor(lua_State* L, T* obj, int argcount, types<CArgs...> t, Args&&... args) {
|
||||
|
||||
template<typename ...CArgs, typename... Args>
|
||||
static void match_constructor(lua_State* L, T* obj, call_syntax syntax, int argcount, types<CArgs...> t, Args&&... args) {
|
||||
if (argcount == sizeof...(CArgs)) {
|
||||
do_constructor( L, obj, argcount, t );
|
||||
do_constructor(L, obj, syntax, argcount, t);
|
||||
return;
|
||||
}
|
||||
match_constructor( L, obj, argcount, std::forward<Args>(args)...);
|
||||
match_constructor(L, obj, syntax, argcount, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static int construct(lua_State* L) {
|
||||
call_syntax syntax = stack::get_call_syntax(L, meta);
|
||||
int argcount = lua_gettop(L);
|
||||
// First argument is now a table that represent the class to instantiate
|
||||
luaL_checktype( L, 1, LUA_TTABLE );
|
||||
|
||||
// Table represents the instance
|
||||
lua_createtable(L, 0, 0);
|
||||
// Set first argument of new to metatable of instance
|
||||
lua_pushvalue(L, 1);
|
||||
|
||||
void* udata = lua_newuserdata(L, sizeof(T));
|
||||
T* obj = static_cast<T*>(udata);
|
||||
match_constructor(L, obj, syntax,
|
||||
argcount - static_cast<int>(syntax),
|
||||
std::common_type<TTypes>::type()...);
|
||||
|
||||
luaL_getmetatable(L, meta.c_str());
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
// Do function lookups in metatable
|
||||
lua_pushvalue(L, 1);
|
||||
lua_setfield(L, 1, "__index");
|
||||
|
||||
|
||||
void* udata = lua_newuserdata( L, sizeof( T ) );
|
||||
T* obj = static_cast<T*>( udata );
|
||||
match_constructor( L, obj, argcount - 1, std::common_type<TTypes>::type( )... );
|
||||
//match_constructor( L, obj, argcount - 1, types<int>( ) );
|
||||
|
||||
luaL_getmetatable(L, meta.c_str());
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setfield(L, -2, "__self");
|
||||
|
||||
return 1;
|
||||
|
||||
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 ludata = stack::get<lightuserdata_t>(L, i);
|
||||
lua_func* func = static_cast<lua_func*>(ludata.value);
|
||||
std::default_delete<lua_func> dx{};
|
||||
dx(func);
|
||||
}
|
||||
|
||||
userdata_t udata = stack::get<userdata_t>(L, 0);
|
||||
/*for(std::size_t i = 0; i < n; ++i) {
|
||||
base_function::base_gc(L, stack::get<lightuserdata_t>(L, i + 1));
|
||||
}*/
|
||||
userdata_t udata = stack::get<userdata_t>(L, 1);
|
||||
T* obj = static_cast<T*>(udata.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");
|
||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||
base_function& fx = *pfx;
|
||||
int r = fx(L);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t n>
|
||||
template<std::size_t n>
|
||||
void build_function_tables() {
|
||||
|
||||
}
|
||||
|
||||
template <std::size_t n, typename... Args, typename Ret, typename... MArgs>
|
||||
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(detail::make_unique<userdata_function<fx_t, T>>(std::move(func)));
|
||||
functiontable.push_back({ functionnames.back().c_str(), &class_func<n>::call });
|
||||
functiontable.push_back({ functionnames.back().c_str(), &base_function::userdata<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(Args&&... args) : userdata(classname, default_constructor, std::forward<Args>(args)...) {}
|
||||
|
||||
template <typename... Args>
|
||||
userdata(std::string name, Args&&... args) : userdata(name, constructors<types<>>(), std::forward<Args>(args)...) {}
|
||||
|
||||
template <typename... Args, typename... CArgs>
|
||||
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>
|
||||
template<typename... Args, typename... CArgs>
|
||||
userdata(std::string name, constructors<CArgs...>, Args&&... args) : luaname(std::move(name)) {
|
||||
functionnames.reserve(sizeof...(args));
|
||||
functiontable.reserve(sizeof...(args));
|
||||
functions.reserve(sizeof...(args));
|
||||
metatable.reserve(sizeof...(args));
|
||||
functionnames.reserve(sizeof...(args) + 2);
|
||||
functiontable.reserve(sizeof...(args) + 3);
|
||||
functions.reserve(sizeof...(args) + 2);
|
||||
build_function_tables<0>(std::forward<Args>(args)...);
|
||||
|
||||
functionnames.push_back("new");
|
||||
functiontable.push_back({ functionnames.back().c_str(), &constructor<CArgs...>::construct });
|
||||
functionnames.push_back("__gc");
|
||||
functiontable.push_back({ functionnames.back().c_str(), &destructor<sizeof...(Args) / 2>::destruct });
|
||||
|
||||
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>
|
||||
template<typename T>
|
||||
const std::string userdata<T>::classname = detail::demangle(typeid(T));
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
const std::string userdata<T>::meta = std::string("sol.stateful.").append(classname);
|
||||
|
||||
}
|
||||
|
|
66
tests.cpp
66
tests.cpp
|
@ -36,6 +36,24 @@ struct fuser {
|
|||
}
|
||||
};
|
||||
|
||||
namespace crapola {
|
||||
struct fuser {
|
||||
int x;
|
||||
fuser( ) : x( 0 ) {
|
||||
}
|
||||
fuser( int x ) : x( x ) {
|
||||
}
|
||||
fuser( int x, int x2 ) : x( x * x2 ) {
|
||||
}
|
||||
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;
|
||||
|
@ -359,15 +377,59 @@ TEST_CASE("tables/userdata", "Show that we can create classes from userdata and
|
|||
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>()));
|
||||
REQUIRE((a.is<sol::userdata_t>()));
|
||||
auto atype = a.get_type();
|
||||
auto btype = b.get_type();
|
||||
auto ctype = c.get_type();
|
||||
REQUIRE((atype == sol::type::table));
|
||||
REQUIRE((atype == sol::type::userdata));
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/userdata constructors", "Show that we can create classes from userdata and use them with multiple destructors") {
|
||||
|
||||
sol::state lua;
|
||||
|
||||
sol::constructors<sol::types<>, sol::types<int>, sol::types<int, int>> con;
|
||||
sol::userdata<crapola::fuser> lc(con, &crapola::fuser::add, "add", &crapola::fuser::add2, "add2");
|
||||
lua.set_class(lc);
|
||||
|
||||
lua.script(
|
||||
"a = crapola_fuser.new(2)\n"
|
||||
"u = a:add(1)\n"
|
||||
"v = a:add2(1)\n"
|
||||
"b = crapola_fuser:new()\n"
|
||||
"w = b:add(1)\n"
|
||||
"x = b:add2(1)\n"
|
||||
"c = crapola_fuser.new(2, 3)\n"
|
||||
"y = c:add(1)\n"
|
||||
"z = c:add2(1)\n"
|
||||
);
|
||||
sol::object a = lua.get<sol::object>("a");
|
||||
auto atype = a.get_type();
|
||||
REQUIRE((atype == sol::type::userdata));
|
||||
sol::object u = lua.get<sol::object>("u");
|
||||
sol::object v = lua.get<sol::object>("v");
|
||||
REQUIRE((u.as<int>() == 3));
|
||||
REQUIRE((v.as<int>() == 5));
|
||||
|
||||
sol::object b = lua.get<sol::object>("b");
|
||||
auto btype = b.get_type();
|
||||
REQUIRE((btype == sol::type::userdata));
|
||||
sol::object w = lua.get<sol::object>("w");
|
||||
sol::object x = lua.get<sol::object>("x");
|
||||
REQUIRE((w.as<int>() == 1));
|
||||
REQUIRE((x.as<int>() == 3));
|
||||
|
||||
sol::object c = lua.get<sol::object>("c");
|
||||
auto ctype = c.get_type();
|
||||
REQUIRE((ctype == sol::type::userdata));
|
||||
sol::object y = lua.get<sol::object>("y");
|
||||
sol::object z = lua.get<sol::object>("z");
|
||||
REQUIRE((y.as<int>() == 7));
|
||||
REQUIRE((z.as<int>() == 9));
|
||||
}
|
Loading…
Reference in New Issue
Block a user