利用c++11新特性来实现一个lua binder,这一次比上次写的超级雏形要完善一些,基本上可以在练习时使用了,要真正投入到项目中,还得继续丰富对类型的处理和调整,待下一篇再写。
上一篇使用了由侯选模板拆分函数参数的写法,这次使用的是variadic template的另一种用法,由待调用的函数(只做类型的分析,无实际功能)和参数包共同完成函数参数的拆分。
相对一些老早就出来的库,这个是非常简陋的。为什么又要多造一个车轮更多的是出于学习的目的。轻装出发,我们用一个包装函数使它可以在Lua中被调用的例子,选择普通的函数,如
int add(int a, int b) {
return a+b;
}
那么手工写一个包装函数大致如下
int lf_add(lua_State* L) {
int a = lua_tonumber(L, 1);
int b = lua_tonumber(L, 2);
int c = a+b;
lua_pushnumber(L, c);
return 1;
}
我们的任务就是完成对这个函数的一般化,就是写一个(应当是一些)模板xLB_adapter,然后传入函数类型add,由编译器生成一个生成包装的函数,这样在Lua环境中就可以调用到它了。
xLB_adapter需要完成的功能大概可分成三个部分:
- 1.把参数从lua_State*中取出来(如果有的话)
- 2.调用C++中的函数,如果有返回值,保存之
- 3.如果返回值,把它压回lua_State*中,并最终返回压入返回值的个数
基本的解决思路是用variadic template来完成,中间的参数存放放到tuple中。
- 任务1用这个完成
xLB_getter<2, idxer_t,typename xLB_vt<A>::type...>::get(L, tuple);
其中idxer_t是根据函数的参数个数(有些函数是没办法确定参数个数的,这个留到以后再干)生成的一个类型,这个类型中啥都没有,就是个序列(不是值,是类型里的信息),
template<int...> struct xLB_idxer{};
就是这个东东,序列包含中int...中(生成这样的序列办法很多,从网上抄了一个)。有了这个序列之后,我们就能一个一个的从lua_State*中把参数提取出来(序列可以做为Lua栈的下标使用)。
这里的2是什么东东(也许你不用管它,它是做为tuple中的函数参数下标与Lua栈下标的一个对准值来用的)。
xLB_vt<A>::type又是个什么东东,用它来把函数的参数类型转化从实际可从lua_State*提取的类型,如函数有一个参数,它的类型是int*,Lua中是没这东东的,我们要把它变成大概是int这样的类型(为什么是大概呢,这个根据需要来,当然对于此次的学习,我只是把它转成int,至于是如何转的,写一堆特化的类模型应该就可以了)。xLB_getter大概象下面这个样子,可以看出来,它啥也不做,除了一些类型的分析,然后就是调用一个xLB_each的东东。
template<int BaseIdx, int...idxs, class...A>
struct xLB_getter<BaseIdx, xLB_idxer<idxs...>, A...> {
static inline void get(lua_State* L, std::tuple<A...>& tuple) {
xLB_each{ (xLB_get<BaseIdx, idxs,std::tuple<A...>,A>(L, tuple),1)... };
}
};
这个xLB_each也是什么也不做,只是让编译器知道,传过来的到xLB_each构造函数的实参应该是一堆参数(0到N,我也不知道N可以是多少)。象上面那样使用xLB_each实际就是variadic template的另一种写法,与上次练习相比,这种写法更简洁,但也更少的可控,没头没尾。(这里的xLB_each为什么要写成类模型呢? 也可以函数模板的,但你会发现,这次练习中使用的大多数是类模型,感觉它操作起类型来更加有威力,如果那一天发现恰恰相反,OMG)
struct xLB_each{ template<class ...T> xLB_each(T...) {} };
- 任务2用这个完成
R r = xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>::call(obj, f, tuple);
这是有返回值的(如果没有返回值呢,我也不知道怎么办,我是通过写了另一个模板来解决没有返回值的问题。如果你有更好的办法,麻烦告诉我QQ158989725,希望你有用QQ,并喜欢用它)。xLB_call大致的实现如
template<class R, class T, class...A, class...B, int...idxs>
struct xLB_call<R (T::*)(A...), xLB_idxer<idxs...>, B...> {
static inline R call(T* obj, R (T::*f)(A...), std::tuple<B...>& tuple) {
return (obj->*f)(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
}
};
你会发现不对劲,没错,这里写的是包装C++类的函数调用,有个obj。这里要做两件事,把参数(中间参数,也许被弄个面目全非了,也许是原样不动)从tuple中取出来,转成能够做为被包装函数的实参的类型(把类型又改回去,多折腾)。最后是调用了被包装的函数。
- 任务3用这个完成
xLB_return_param<RPIdxer,typename xLB_vt<A>::type...>::return_param(L, tuple, return_count);
xLB_vt前面已经讲过,这里多了一个叫RPIdxer,就是返回哪些参数到Lua中(没错,Lua是支持多参数返回的),那RPIdxer是个什么东东呢,它实际是前面说过的序列xLB_idxer,不过它的序列是由你来决定的,不是根据函数参数来决定的,比如你想返回10参数中的第5个(这个比较好只,已经写出来了,比如你想返回一个固定值还是什么其它的,那将是一个很好的家庭作业)。对了,还有一个return_count,如果有返回就修改它(+1),最终将把它作为包装函数的返回值返回给Lua。
template<int...RPI, class...A>
struct xLB_return_param<xLB_idxer<RPI...>,A...> {
static inline void return_param(lua_State* L,
const std::tuple<A...>& tuple, int& return_count) {
xLB_each{ (xLB_pusher(L, std::get<RPI>(tuple), return_count), 1)... };
}
};
以下是xlb源代码和一个例子(仔细瞧瞧,有问题,好像R没做类型转换)。
xlb.h
#ifndef _XLB_H
#define _XLB_H
// rpc object used in lua
//#include <ns/nr.h>
#include <nbbase.h>
using namespace loon;
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
} // lua header files
/*---------------------------------------------------------------------------
xLB_ludwrap : light user data wrapp as user data
-----------------------------------------------------------------------------*/
/* @struct xLB_ludwrap
* This template used to wrapper lightuserdata as userdata, and then we can
* set metatable on its. It's instance life managered by C++ not by Lua. */
template<typename T> struct xLB_ludwrap {
//operator T*(){ return __ptr; }
T* ptr(){ return __ptr; }
T* operator->() { return __ptr; }
//xLB_ludwrap& operator=(T* ptr){ __ptr = ptr; }
//bool operator==(T* ptr){ return __ptr == ptr; }
//bool operator==(const xLB_ludwrap<T>& r){ return __ptr == r.__ptr; }
xLB_ludwrap(T* ptr, bool del=false) : __ptr(ptr), __del(del) {}
virtual ~xLB_ludwrap(){ if (__del) { delete __ptr; } }
protected:
T* __ptr; /**< real object */
bool __del; /**< delete __ptr when xLB_ludwrap was release */
}; // end of xLB_ludwrap
/*---------------------------------------------------------------------------
xLB_pusher
-----------------------------------------------------------------------------*/
template<typename T>
inline void xLB_pusher(lua_State* L, T r, int& return_count) {
lua_pushnumber(L, r); ++return_count;
}
template<typename R, typename T>
inline void xLB_pusher(lua_State* L, R& r, int& return_count) {}
template<typename T>
inline void xLB_pusher(lua_State* L, T* r, int& return_count) {
lua_pushvalue(L, 1); ++return_count;
}
template<typename T>
inline void xLB_pusher(lua_State* L, char* r, int& return_count) {
lua_pushstring(L, r); ++return_count;
}
template<typename T>
inline void xLB_pusher(lua_State* L, double r, int& return_count) {
lua_pushnumber(L, r); ++return_count;
}
template<typename T>
inline void xLB_pusher(lua_State* L, long r, int& return_count) {
lua_pushnumber(L, r); ++return_count;
}
template<typename T>
inline void xLB_pusher(lua_State* L, bool r, int& return_count) {
lua_pushboolean(L, r); ++return_count;
}
/*---------------------------------------------------------------------------
xLB_make_indexes_impl
-----------------------------------------------------------------------------*/
template<int...> struct xLB_idxer{};
template<int...RPI> using xLB_rpi = xLB_idxer<RPI...>; // xLB_idxer alias
template<int I, class IndexTuple, class... Types>
struct xLB_make_indexes_impl;
template<int I, int... Indexes, class T, class ... Types>
struct xLB_make_indexes_impl<I, xLB_idxer<Indexes...>, T, Types...> {
typedef typename xLB_make_indexes_impl
<I + 1, xLB_idxer<Indexes..., I>, Types...>::type type;
}; // end of xLB_make_indexes_impl
template<int I, int... Indexes>
struct xLB_make_indexes_impl<I, xLB_idxer<Indexes...> > {
typedef xLB_idxer<Indexes...> type;
}; // end of xLB_make_indexes_impl
template<typename ... Types>
struct xLB_toidxer :
xLB_make_indexes_impl<0, xLB_idxer<>, Types...> {};
/*---------------------------------------------------------------------------
xLB_get param from lua_State
-----------------------------------------------------------------------------*/
template<int BaseIdx, int idx, class TUP, class V>
struct xLB_get_impl {
static inline void go(lua_State* L, TUP& tuple) { }
};
template<int BaseIdx, int idx, class TUP>
struct xLB_get_impl<BaseIdx, idx, TUP, int> {
static inline void go(lua_State* L, TUP& tuple) {
std::get<idx>(tuple) = lua_tointeger(L, idx+BaseIdx);
}
};
template<int BaseIdx, int idx, class TUP>
struct xLB_get_impl<BaseIdx, idx, TUP, double> {
static inline void go(lua_State* L, TUP& tuple) {
std::get<idx>(tuple) = lua_tonumber(L, idx+BaseIdx);
}
};
/*
template<class TUP, class T>
struct xLB_get_impl<0, TUP, T*> {
static void go(lua_State* L, TUP& tuple) {
std::get<0>(tuple) = reinterpret_cast<T*>(lua_touserdata(L, 2));
}
};
*/
template<int BaseIdx, int idx, class TUP, class V>
inline void xLB_get(lua_State* L, TUP& tuple) {
xLB_get_impl<BaseIdx, idx, TUP, V>::go(L, tuple);
// in R (T::*)(A...)
//<0,1,...,n> 0=param1,lua idx=2; lua idx=1 is obj
// in T (*)(A...)
//<0,1,...,n> 0=param1,lua idx=1
}
/*---------------------------------------------------------------------------
xLB_getter get arguments from lua_State and save in tuple
-----------------------------------------------------------------------------*/
struct xLB_each{ template<class ...T> xLB_each(T...) {} };
/*
template<class ...A, int ...idxs> inline void
xLB_getter(lua_State* L, std::tuple<A...>& tuple, xLB_idxer<idxs...>&) {
xLB_each{ (xLB_get<idxs,std::tuple<A...>,A>(L, tuple),1)... };
}
*/
template<int BaseIdx, class IDXER, class...PARAM>
struct xLB_getter {};
template<int BaseIdx, int...idxs, class...A>
struct xLB_getter<BaseIdx, xLB_idxer<idxs...>, A...> {
static inline void get(lua_State* L, std::tuple<A...>& tuple) {
xLB_each{ (xLB_get<BaseIdx, idxs,std::tuple<A...>,A>(L, tuple),1)... };
}
};
/*---------------------------------------------------------------------------
xLB_gv1
-----------------------------------------------------------------------------*/
//template<class T1, class T2>inline T1 xLB_gv1(const T2& v) { }
//template<class T1>inline T1& xLB_gv1(T1& v) { return v; }
//template<class T1> inline T1* xLB_gv1(T1& v) { return &v; }
//int* xLB_gv1(int& v) { return &v; }
template<class To, class From> struct xLB_gv1 { };
template<class T1> struct xLB_gv1<T1, T1> {
inline static T1& val(T1& v) { return v; }
};
template<> struct xLB_gv1<int*, int> {
inline static int* val(int& v) { return &v; }
};
template<> struct xLB_gv1<int&, int> {
inline static int& val(int& v) { return v; }
};
/*---------------------------------------------------------------------------
xLB_call call obj method, obj=tuple[0] and arguments=tuple[1...]
-----------------------------------------------------------------------------*/
//auto wrap = reinterpret_cast<T*>(std::get<0>(tuple));
//auto obj = wrap->ptr();
//return (obj->*f)(std::get<idxs>(tuple)...);
//auto wrap = reinterpret_cast<T*>(std::get<0>(tuple));
//(wrap->ptr()->*f)(std::get<idxs>(tuple)...);
/*
template<class R, class T, class ...B, class F, class ...A, int ...idxs> inline R
xLB_call(F f, T* obj, std::tuple<A...>& tuple, xLB_idxer<idxs...>&) {
if (obj) {
return (obj->*f)(xLB_gv1<B,A>::val(std::get<idxs>(tuple))...);
} else {
nb_warn(true, "obj expected but nil");
return R{};
}
}
*/
template<class FT, class, class...A> struct xLB_call{};
template<class R, class T, class...A, class...B, int...idxs>
struct xLB_call<R (T::*)(A...), xLB_idxer<idxs...>, B...> {
static inline R call(T* obj, R (T::*f)(A...), std::tuple<B...>& tuple) {
return (obj->*f)(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
}
};
template<class T, class...A, class...B, int...idxs>
struct xLB_call<void (T::*)(A...), xLB_idxer<idxs...>, B...> {
static inline void call(T* obj, void (T::*f)(A...), std::tuple<B...>& tuple) {
(obj->*f)(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
}
};
template<class...A, class...B, int...idxs>
struct xLB_call<void (*)(A...), xLB_idxer<idxs...>, B...> {
static inline void call(void (*f)(A...), std::tuple<B...>& tuple) {
f(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
}
};
template<class...A, class...B, class R, int...idxs>
struct xLB_call<R (*)(A...), xLB_idxer<idxs...>, B...> {
static inline R call(R (*f)(A...), std::tuple<B...>& tuple) {
return f(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
}
};
/*
template<class T, class ...B, class F, class ...A, int ...idxs> inline void
xLB_caller_void(F f, T* obj, std::tuple<A...>& tuple, xLB_idxer<idxs...>&) {
assert(obj!=nullptr);
(obj->*f)(xLB_gv1<B,A>::val(std::get<idxs>(tuple))...);
}
*/
/*
int f(int i) { std::cout << "f(int) " << i << std::endl; return i*2; }
double f(double d) { std::cout << "f(double) " << d << std::endl; return d*2; }
template<class ... A>inline void pass(A&&...) {}
template<class ... A>inline void expand(A&&...a) {
pass(f(a)...);
}
template<class ... A>inline void expand2(A&&...a) {
pass2{(f(a),1)...};
}
struct pass2{
template<typename ...T> pass2(T...) {}
};
template<class TUPLE>
struct class_operator {
template<int j>
void get(int i) { std::get<j>(tuple) = i; std::cout << j << " class_operator(int) " << i << std::endl; }
template<int j>
void get(double d) { std::get<j>(tuple) = d; std::cout << j << " class_operator(doule) " << d << std::endl; }
TUPLE tuple;
unsigned index = 0;
};
template<class ...A, int ...idxs>
void pass3(class_operator<std::tuple<A...>>& class_, index_tuple<idxs...>& idx, A&...a) {
//pass2{(std::get<idxs>(class_.tuple),1)...};
pass2{(class_.get<idxs>(a),1)...};
}
template<class ...A>inline void expand3(A&&...a) {
typedef std::tuple<A...> test_tuple;
class_operator<test_tuple> class_;
class_.index = sizeof...(A);
typename make_indexes<A...>::type indexer;
//pass2{(class_.get<0>(a),1)...};
pass3(class_, indexer, a...);
std::cout << std::get<0>(class_.tuple) << std::endl;
}
*/
template<typename T> struct xLB_xotrait;
template<typename T> struct xLB_function;
template<typename T> struct xLB_xobase;
#define luaL_reg luaL_Reg
/*---------------------------------------------------------------------------
xlb function
-----------------------------------------------------------------------------*/
/** This function create metatable with lua api and set __index and metatable
* to itself and make it have key weak feature. */
void xLB_newmetatable(lua_State* L, const char* LibName, luaL_Reg* Lreg);
/** This function set metatable named LibName to userdata at top of stack. */
void xLB_userdata(lua_State* L, const char* LibName, lua_Number N = 0);
/*---------------------------------------------------------------------------
lua userdata and C++ object
-----------------------------------------------------------------------------*/
/** if the object specify by index is userdata then
* 1. if it is instance of type xLB_ludwrap<T> then get T* address from it;
* 2. if it is derived from T* then get T* from userdata;
* otherwise return nullptr; */
template<typename T, const char meta[]>
T* xLB_getuserdata(lua_State* L, int index, xLB_ludwrap<T>** pWp = 0) {
typedef xLB_ludwrap<T> w_t;
T* r = 0;
//nb_warn(true, "%d-%d", lua_isuserdata(L, index), index);
if (lua_isuserdata(L, index)) {
//auto wp = reinterpret_cast<w_t*>(luaL_checkudata(L, index, meta));
auto wp = reinterpret_cast<w_t*>(lua_touserdata(L, index));
//auto wp = dynamic_cast<w_t*>(lua_touserdata(L, index));
//nb_warn(true, "%x", wp);
if (wp) { r = wp->ptr(); if (pWp) { *pWp = wp; } }
//else { r = lua_touserdata(L, index); }
//else { nb_warn(true, "not wrap"); }
} //else { nb_warn(true, "userdata expected"); }
//nb_warn(true, "%x", r);
return r;
}
/*
template<typename T, const char meta[]>
T* xLB_newuserdata(lua_State* L) {
auto place = (T*)(lua_newuserdata(L, sizeof(T)));
xLB_userdata(L, meta, 0);
return place;
}
template<typename T, const char meta[]>
void xLB_wraplud(lua_State* L, T* obj) {
typedef xLB_ludwrap<T> w_t;
auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
new(place) w_t(obj);
xLB_userdata(L, meta, 0);
}
*/
/* Wrap xo as Lua ud, and Lua do not charge object's life. */
template<typename T>
void xLB_wrapxo(lua_State* L, T* obj) {
typedef xLB_ludwrap<T> w_t;
auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
new(place) w_t(obj/*,false*/);
xLB_userdata(L, xLB_xotrait<T>::meta_name, 0);
}
template<typename T, const char meta[]>
void xLB_objasud(lua_State* L, T* obj) {
typedef xLB_ludwrap<T> w_t;
auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
new(place) w_t(obj, true);
xLB_userdata(L, meta, 0);
}
/* Wrap xo as Lua ud, means Lua charge object's life. */
template<typename T>
void xLB_xoasud(lua_State* L, T* obj) {
typedef xLB_ludwrap<T> w_t;
w_t* place = static_cast<w_t*>(lua_newuserdata(L, sizeof(w_t)));
new(place) w_t(obj, true);
xLB_userdata(L, xLB_xotrait<T>::meta_name, 0);
}
template<typename T, const char meta[]>
int xLB_gcobj(lua_State* L) {
xLB_ludwrap<T>* wp = 0;
xLB_getuserdata<T, meta>(L, 1, &wp);
if (wp) { wp->~xLB_ludwrap<T>();}
return 0;
}
template<typename T, typename...A>
T* xLB_newxo(lua_State* L, A...arg_metas) {
T* pobj = new T(arg_metas...);
xLB_objasud<T, xLB_xotrait<T>::meta_name>(L, pobj);
return pobj;
}
template<typename T>
int xLB_gcxo(lua_State* L) {
xLB_ludwrap<T>* wp = nullptr;
xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, 1, &wp);
//nb_warn(true, xLB_xotrait<T>::meta_name);
if (wp) { wp->~xLB_ludwrap<T>(); }
//nb_warn(true, "...>");
return 0;
}
/*---------------------------------------------------------------------------
xLB binder
-----------------------------------------------------------------------------*/
template<typename T>
unique_ptr<xLB_xotrait<T>> xLB_newxobinder() {
return unique_ptr<xLB_xotrait<T>>(new xLB_xotrait<T>());
}
template<typename T>
void xLB_bindxo(lua_State* L, const char* ns=nullptr) {
xLB_xotrait<T>().reg(L, ns);
}
template<typename T>
void xLB_regxo(lua_State* L, xLB_xotrait<T>* xo) { xo->reg(L); }
template<typename T>
void xLB_xoglobal(lua_State* L, T* obj, const char* name) {
xLB_wrapxo(L, obj);
lua_setglobal(L, name);
}
/*---------------------------------------------------------------------------
xLB ns table
-----------------------------------------------------------------------------*/
#define xLB_pushtable(L, tbl, name, ns) tbl().reg(L, name, ns);
void xLB_newnstable(lua_State* L, const char* name, const char* ns);
void xLB_newnstable(lua_State* L, const char* tn, int index);
//void xLB_getnstable(lua_State* L, const char* name, const char* ns);
/*---------------------------------------------------------------------------
xo macro
-----------------------------------------------------------------------------*/
#define xLB_xodefine(xo_t) \
template<> const char xLB_xobase<xo_t>::meta_name[]="xLB_"#xo_t; \
template<> const char xLB_xobase<xo_t>::type_name[]=#xo_t; \
template<> xLB_namelist_t xLB_xobase<xo_t>::super_name_list=xLB_namelist_t();
#define xLB_xodeclare(xo_t) \
template<> struct xLB_xotrait<xo_t> : public xLB_xobase<xo_t>
/*---------------------------------------------------------------------------
xLB_method
-----------------------------------------------------------------------------*/
template<typename T>struct xLB_method {
using type =int (*)(lua_State*, T*);
};
template<typename R, typename T, typename... A>
struct xLB_method<R (T::*)(A...) > {
using type = R(T::*)(A...);
};
template<typename R, typename T, typename... A>
struct xLB_method<R (T::*)(A...) const > {
using type = R(T::*)(A...) const;
};
template<typename T>
T* xLB_getxo(lua_State* L, int index) {
return xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, index);
}
template<typename T, typename xLB_method<T>::type f>
int xLB_xomethod(lua_State* L) {
int rc = 0;
T* obj = xLB_getxo<T>(L, 1);
if (obj) rc = f(L, obj);
//else nb_warn(true, "%s not registered", xLB_xotrait<T>::meta_name);
return rc;
}
/*---------------------------------------------------------------------------
xLB_vt
-----------------------------------------------------------------------------*/
template<class Tx>struct xLB_vt { using type = Tx; };
template<class Tx>struct xLB_vt<Tx&> { using type = typename xLB_vt<Tx>::type; };
template<>struct xLB_vt<int*> { using type = int; };
//using tuple_t = std::tuple<wrap_t*, typename std::remove_reference<A>::type...>;
//
//using tuple_t = std::tuple<wrap_t*, typename xLB_vt<A>::type...>;
//using idxer_t = typename xLB_toidxer<wrap_t*, A...>::type;
//using tuple_t = std::tuple<wrap_t*, typename std::remove_reference<A>::type...>;
//
//using tuple_t = std::tuple<wrap_t*, typename xLB_vt<A>::type...>;
//using idxer_t = typename xLB_toidxer<wrap_t*, A...>::type;
/*---------------------------------------------------------------------------
xLB_return_param
-----------------------------------------------------------------------------*/
/*
template<int...RPI, class...A>
void xLB_return_param(lua_State* L,
const std::tuple<A...> &tuple, xLB_idxer<RPI...>&, int& return_count) {
xLB_each{ (xLB_pusher(L, std::get<RPI>(tuple), return_count),1)... };
}
*/
template<class, class...> struct xLB_return_param {};
template<int...RPI, class...A>
struct xLB_return_param<xLB_idxer<RPI...>,A...> {
static inline void return_param(lua_State* L,
const std::tuple<A...>& tuple, int& return_count) {
xLB_each{ (xLB_pusher(L, std::get<RPI>(tuple), return_count), 1)... };
}
};
//R r = xLB_call<R,T,A...>(f, obj, tuple, indexer);
//xLB_caller_void<T,A...>(f, obj, tuple, indexer);
//idxer_t indexer;
//idxer_t indexer;
//RPIdxer rpi_idxer;
//xLB_return_param(L, tuple, rpi_idxer, return_count);
//RPIdxer rpi_idxer;
//xLB_return_param(L, tuple, rpi_idxer, return_count);
/*---------------------------------------------------------------------------
xLB_adapter
-----------------------------------------------------------------------------*/
template<class R, class T, class F, F f, class RPIdxer, class...A>
int xLB_adapter(lua_State* L) {
using wrap_t = xLB_ludwrap<T>;
using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
xLB_getter<2, idxer_t,typename xLB_vt<A>::type...>
::get(L, tuple);
auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
assert(wrap != nullptr);
auto obj = wrap->ptr(); assert(obj != nullptr);
R r = xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
::call(obj, f, tuple);
int return_count = 0;
xLB_pusher(L, r, return_count);
xLB_return_param<RPIdxer,typename xLB_vt<A>::type...>
::return_param(L, tuple, return_count);
return return_count;
}
template<class T, class F, F f, class RPIdxer, class...A>
int xLB_adapter_void(lua_State* L) {
using wrap_t = xLB_ludwrap<T>;
using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
xLB_getter<2, idxer_t,typename xLB_vt<A>::type...>
::get(L, tuple);
auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
assert(wrap != nullptr);
auto obj = wrap->ptr(); assert(obj != nullptr);
xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
::call(obj, f, tuple);
int return_count = 0;
xLB_return_param<RPIdxer,typename xLB_vt<A>::type...>
::return_param(L, tuple, return_count);
return return_count;
}
template<class FT, FT f, int...> struct xLB_CFunc {};
template<class...A, void (*f)(A...), int...RPI>
struct xLB_CFunc<void (*)(A...), f, RPI...> {
static int adapter(lua_State* L) {
using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
xLB_getter<1, idxer_t,typename xLB_vt<A>::type...>
::get(L, tuple);
xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
::call(f, tuple);
int return_count = 0;
xLB_return_param<xLB_idxer<RPI...>,typename xLB_vt<A>::type...>
::return_param(L, tuple, return_count);
return return_count;
}
};
template<class...A, class R, R (*f)(A...), int...RPI>
struct xLB_CFunc<R (*)(A...), f, RPI...> {
static int adapter(lua_State* L) {
using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
xLB_getter<1, idxer_t,typename xLB_vt<A>::type...>
::get(L, tuple);
R r = xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
::call(f, tuple);
int return_count = 0;
xLB_pusher(L, r, return_count);
xLB_return_param<xLB_idxer<RPI...>,typename xLB_vt<A>::type...>
::return_param(L, tuple, return_count);
return return_count;
}
};
/*
template<typename T, typename... A, void (T::*f)(A...)>
int xLB_adapter(lua_State* L) {
using arg_tuple_t = std::tuple<T*,A...>;
using idxer_t = typename xLB_toidxer<T*,A...>::type;
idxer_t indexer;
arg_tuple_t tuple;
xLB_getter(L, tuple, indexer);
xLB_call<f>(tuple);
return 0;
}
*/
/*---------------------------------------------------------------------------
xLB_return_void
-----------------------------------------------------------------------------*/
template<typename Tx> struct xLB_return_void {
static const bool value = true;
};
template<typename Tx, class R, class ...A>
struct xLB_return_void<R (Tx::*)(A...)> {
static const bool value = std::is_void<R>::value;
};
/*---------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
template<typename T> struct xLB_xotrait{ static char meta[]; };
typedef std::vector<nbCPChar> xLB_namelist_t;
int xLB_search(lua_State* L, nbCPChar method_name, const xLB_namelist_t& nlst);
int xLB_rawsearch(lua_State* L, nbCPChar method_name, nbCPChar meta_name);
/*---------------------------------------------------------------------------
xLB_proxy
-----------------------------------------------------------------------------*/
//template<class Tx, Tx, bool, int...RPI> struct xLB_proxy;
template<class Tx, Tx, bool, class> struct xLB_proxy;
template<class Tx, class R, class ...A, R (Tx::*f)(A...), int...RPI>
struct xLB_proxy<R (Tx::*)(A...), f, false, xLB_idxer<RPI...>> {
static inline void b(xLB_xobase<Tx>* xobinder, const char fn[]) {
xobinder->rg_meta.push_back({fn,
&xLB_adapter<R, Tx, R (Tx::*)(A...), f, xLB_idxer<RPI...>, A...>
});
}
};
template<class Tx, class ...A, void (Tx::*f)(A...), int...RPI>
struct xLB_proxy<void (Tx::*)(A...), f, true, xLB_idxer<RPI...>> {
static inline void b(xLB_xobase<Tx>* xobinder, const char fn[]) {
xobinder->rg_meta.push_back({fn,
xLB_adapter_void<Tx, void (Tx::*)(A...), f, xLB_idxer<RPI...>, A...>
});
}
};
/*---------------------------------------------------------------------------
xLB_xobase
-----------------------------------------------------------------------------*/
template<typename X>
struct xLB_xobase {
typedef X T;
typedef xLB_xobase self_t;
typedef xLB_xobase* this_t;
typedef xLB_xotrait<T> trait_t;
typedef std::vector<luaL_reg> regs_t;
static const char meta_name[];
static const char type_name[];
static xLB_namelist_t super_name_list;
regs_t rg_meta;
regs_t rg_type;
virtual ~xLB_xobase() {}
static int index_implement(lua_State* L) { //__index(t,k)
auto method_name = luaL_optlstring(L, 2, "", nullptr);
int nFound = xLB_rawsearch(L, method_name, meta_name);
if (!nFound) {
nFound = xLB_search(L, method_name, super_name_list);
}
return nFound;
}
void newxometatable(lua_State* L) {
luaL_newmetatable(L, trait_t::meta_name);
lua_pushstring(L, "__index");
lua_pushcfunction(L, index_implement);
lua_rawset(L, -3);
// set metatable.metatable to itself
lua_pushvalue(L, -1);
lua_setmetatable(L, -2);
luaL_setfuncs(L, &rg_meta[0], 0);
lua_pop(L, 1); // pop metatable
}
template<class SUPER_XO> void super() {
super_name_list.push_back(xLB_xotrait<SUPER_XO>::meta_name);
}
template<lua_CFunction f> void c(const char fn[]="new") {
rg_type.push_back({fn,f});
}
//inline void pushf(regs_t& rs, const char* n, lua_CFunction f) {
luaL_reg r{n,f}; rs.push_back(r);
//rs.push_back({n, f});
//}
//template<lua_CFunction f> void c() { pushf(rg_type, "new", f); }
//pushf(rg_type, fn, f);
//pushf(rg_meta, fn, xLB_xomethod<T, f>);
//pushf(rg_meta, fn, f);
//pushf(rg_meta, nullptr, nullptr);
//xLB_newmetatable(L, trait_t::meta_name, &rg_meta[0]);
//pushf(rg_type, nullptr, nullptr);
/*---------------------------------------------------------------------------
bind function
-----------------------------------------------------------------------------*/
template<typename xLB_method<T>::type f> void b(const char fn[]) {
rg_meta.push_back({fn, xLB_xomethod<T, f>});
}
template<lua_CFunction f> void b(const char fn[]) {
rg_meta.push_back({fn,f});
}
//template<class FT, FT f, int...RPI> void b(const char fn[]) {
// xLB_proxy<FT, f, xLB_return_void<FT>::value, RPI...>::b(this, fn);
// }
template<class FT, FT f, class RPIs = xLB_idxer<>> void b(const char fn[]) {
xLB_proxy<FT, f, xLB_return_void<FT>::value, RPIs>::b(this, fn);
}
void d() { b<xLB_gcxo<T>>("__gc"); }
void reg(lua_State* L, const char* ns = nullptr) {
if (0 < rg_meta.size()) {
rg_meta.push_back({nullptr,nullptr});
newxometatable(L);
}
if (0 < rg_type.size()) {
rg_type.push_back({nullptr,nullptr});
luaL_newlib(L, &rg_type[0]);
if (ns && strlen(ns)) {
lua_getglobal(L, ns);
if (LUA_TTABLE != lua_type(L, -1)) {
lua_pop(L, 1);
lua_newtable(L);
lua_setglobal(L, ns);
lua_getglobal(L, ns);
}
lua_pushstring(L, trait_t::type_name);
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pop(L, 2);
}
}
}
//static T* getobj(lua_State* L, int index) {
//return xLB_getxo<T>(L, index);
//}
}; // end of xLB_xobase
//inline void pushf(regs_t& rs, const char* n, lua_CFunction f) {
//luaL_reg r{n,f}; rs.push_back(r);
//}
//pushf(rg_table, "new", f);
//pushf(rg_table, fn, f);
//pushf(rg_table, nullptr, nullptr);
//lua_newtable(L);
//luaL_register(L, nullptr, &rg_table[0]);
//pushf(rg_table, nullptr, nullptr);
//lua_newtable(L);
//luaL_register(L, nullptr, &rg_table[0]);
/*---------------------------------------------------------------------------
xLB_table
-----------------------------------------------------------------------------*/
template<typename X>
struct xLB_table {
typedef X T;
typedef xLB_table self_t;
typedef xLB_table* this_t;
typedef std::vector<luaL_reg> regs_t;
virtual ~xLB_table() {}
regs_t rg_table;
template<lua_CFunction f> void c(const char fn[]) {
rg_table.push_back({fn,f});
}
template<lua_CFunction f>
void b(const char fn[]) {
rg_table.push_back({fn,f});
}
void reg(lua_State* L, const char* tn, const char* ns = 0) {
if (0 < rg_table.size()) {
rg_table.push_back({nullptr,nullptr});
luaL_newlib(L, &rg_table[0]);
if (ns && strlen(ns)) {
lua_getglobal(L, ns);
int t = lua_type(L, -1);
if (LUA_TNIL == t || LUA_TTABLE != t ) {
lua_pop(L, 1);
lua_newtable(L);
lua_setglobal(L, ns);
lua_getglobal(L, ns);
}
lua_pushstring(L, tn);
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pop(L, 2);
}
}
}
void reg(lua_State* L, const char* tn, int index = 0) {
if (0 < rg_table.size()) {
rg_table.push_back({nullptr,nullptr});
lua_pushstring(L, tn);
luaL_newlib(L, &rg_table[0]);
if (index < 0) { index-=2; }
if (index) { lua_rawset(L, index); }
}
}
}; // end of xLB_table
#endif // end of __XLB_H__
xlb.cpp
#include <ns/xlb.h>
/*---------------------------------------------------------------------------
xLB_pusher
-----------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
lux_
-----------------------------------------------------------------------------*/
void xLB_newmetatable(lua_State* L, const char* LibName, luaL_Reg* Lreg) {
luaL_newmetatable(L, LibName);
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_rawset(L, -3);
// set metatable to "key" weak table
//lua_pushstring(L, "__mode");
//lua_pushstring(L, "k");
//lua_rawset(L, -3);
// set metatable.metatable to itself
lua_pushvalue(L, -1);
lua_setmetatable(L, -2);
//luaL_register(L, nullptr, Lreg);
luaL_setfuncs(L, Lreg, 0/*no upvalue for funcs to share*/);
lua_pop(L, 1); // pop metatable
}
int xLB_search(lua_State* L, nbCPChar method_name, const xLB_namelist_t& nlst) {
int nFound = 0;
for (auto meta_name : nlst) {
lua_getfield(L, LUA_REGISTRYINDEX, meta_name);
if (!lua_istable(L, -1)) {
nb_warn(true, "%s not registered", meta_name);
return 0;
} else {
lua_pushstring(L, method_name);
lua_gettable(L, -2);
lua_replace(L, -2);
nFound = (lua_isnil(L, -1) ? 0 : 1);
if (nFound) break;
}
}
return nFound;
}
int xLB_rawsearch(lua_State* L, nbCPChar method_name, nbCPChar meta_name) {
//nb_warn(true, "search: %s in %s", method_name, meta_name);
lua_getfield(L, LUA_REGISTRYINDEX, meta_name);
if (!lua_istable(L, -1)) {
nb_warn(true, "%s not registered", meta_name);
return 0;
} else {
lua_pushstring(L, method_name);
lua_rawget(L, -2);
lua_replace(L, -2);
return (lua_isnil(L, -1) ? 0 : 1);
}
}
void xLB_userdata(lua_State* L, const char* LibName, lua_Number N) {
// s: 1(ud)
int inew = luaL_newmetatable(L, LibName); // s: 1(ud), 2(metatable)
//if (inew) throw std::logic_error("metatable muse be registered");
nb_warn(inew, "xLB-Error: %d %s", inew, LibName);
//lua_pushvalue(L, -2); // duplicate userdata as key
//lua_pushnumber(L, N); // value:0 arbitrary
//lua_settable(L, -3); // metatable[userdata] = value(0)
lua_setmetatable(L, -2); // userdata.metatable = metatable
}
void xLB_newnstable(lua_State* L, const char* name, const char* ns) {
lua_getglobal(L, ns);
if (LUA_TTABLE == lua_type(L, -1)) {
lua_pushstring(L, name);
lua_newtable(L);
lua_rawset(L, -3);
}
lua_pop(L, 1);
}
void xLB_newnstable(lua_State* L, const char* tn, int index) {
lua_pushstring(L, tn);
lua_newtable(L);
if (index < 0) { index-=2; }
lua_rawset(L, index);
}
/*
void xLB_getnstable(lua_State* L, const char* name, const char* ns) {
lua_getglobal(L, ns);
lua_pushlstring(L, name, strlen(name));
lua_rawget(L, -2);
lua_insert(L, -2);
lua_pop(L, 1);
}
*/
调用xlb
xlbinder.h
#ifndef _XLBINDER_H
#define _XLBINDER_H
#include <ns/xlb.h>
#include <type_traits>
struct clsB {
void b() { printf("clsB::b() called\n"); }
};
xLB_xodeclare(clsB) {
xLB_xotrait() {
b<decltype(&clsB::b), &clsB::b>("b");
}
};
struct clsA : public clsB {
int Add(int a, int& b);
int Del(int* a);
int Modify(int& a);
void NoReturn(int a);
}; // end of clsA
void foo(int a);
int g(int a);
xLB_xodeclare(clsA) {
xLB_xotrait() {
super<clsB>();
//1.
//lua_CFunction p = xLB_adapter<int, clsA, decltype(&clsA::Add), &clsA::Add, int, int>;
//b<xLB_adapter<int, clsA, decltype(&clsA::Add), &clsA::Add, int, int>>("Add");
//2.
//proxy<decltype(&clsA::Add), &clsA::Add, false>::b(this, "Add");
//b<decltype(&clsA::Add), &clsA::Add>("Add");
b<decltype(&clsA::Add), &clsA::Add, xLB_rpi<1,0>>("Add");
//b<decltype(&clsA::Add), &clsA::Add,xLB_idxer<1,0>>("Add");
//b<decltype(&clsA::Del), &clsA::Del>("Del");
b<decltype(&clsA::NoReturn), &clsA::NoReturn, xLB_idxer<0>>("NoReturn");
//proxy<int (clsA::*)(int,int), &clsA::Add, false>::b(this, "Add");
//proxy<int (clsA::*)(int), &clsA::Add, false>::b(this, "Add2");
//proxy<decltype(&clsA::Modify), &clsA::Modify, false>::b(this, "Modify");
//proxy<decltype(&clsA::NoReturn), &clsA::NoReturn, true>::b(this, "NoReturn");
}
};
#endif
xlbinder.cpp
#include "xlbinder.h"
xLB_xodefine(clsA);
xLB_xodefine(clsB);
int clsA::Add(int a, int& b) {
printf("clsA::Add(%d,%d):%d called\n", a,b,a+b);
b+=123;
return a+b;
}
int clsA::Del(int* a) { printf("obj:Del called: %d\n", *a); return *a = 2; };
int clsA::Modify(int& a) { return a*=2; }
void clsA::NoReturn(int a) { printf("obj:NoReturn called: %d\n", a*3); }
void foo(int a) {
printf("foo called: %d\n", a);
}
int g(int a) {
printf("g called: %d\n", a);
return a+2;
}
int main() {
std::cout << "xLB_adapter test ... \n";
auto L = luaL_newstate();
luaL_openlibs(L);
xLB_bindxo<clsB>(L);
xLB_bindxo<clsA>(L);
clsA obj;
xLB_xoglobal<clsA>(L, &obj, "obj");
luaL_dostring(L, "print('Lua{');");
luaL_dostring(L, "print('getmetatable(obj)={');");
luaL_dostring(L, "for k,v in pairs(getmetatable(obj)) do print(' ' .. k .. '=' .. tostring(v)); end");
luaL_dostring(L, "print('}');");
luaL_dostring(L, "print(obj:Add(99,2));");
//luaL_dostring(L, "print('obj:Add(99,2)=' .. tostring(obj:Add(99,2)));");
//luaL_dostring(L, "d = obj:Del(8);");
//luaL_dostring(L, "print('obj:Del(8)=' .. tostring(d));");
//luaL_dostring(L, "print('obj:Modify(8)=' .. tostring(obj:Modify(8)));");
luaL_dostring(L, "x = obj:NoReturn(8); ");
luaL_dostring(L, "print('obj:NoReturn(8)=' .. tostring(x));");
//---
//auto x = &xLB_CFunc<decltype(&foo), &foo>::voidfunc;
//&xLB_CFunc<decltype(&foo), &foo>::voidfunc
lua_register(L, "foo", &(xLB_CFunc<decltype(&foo), &foo>::adapter));
luaL_dostring(L, "x = foo(1901); print(tostring(x));");
lua_register(L, "g", &(xLB_CFunc<decltype(&g), &g, 0>::adapter));
luaL_dostring(L, "print(g(1999));");
//---
luaL_dostring(L, "obj:b()");
lua_close(L);
printf("}\n");
return 0;
}
//inline void xLB_pusher(lua_State* L, int r, int& return_count) {
//lua_pushinteger(L, r); ++return_count;
//}