书接上一回,说到要继续丰富对类型的处理。那么如何才能做到呢,应该是要支持自定义的,所以这一回要讲的就是在前面的基础上,增加支持自定义部分,其中包含以下几个部分

  • 函数的默认参数设置,包括有几个默认参数和如何设置这些默认参数;
  • 可以做为返回值的参数下标(Lua支持多值返回);
  • 如何将函数的结果和当做返回值的函数的参数压入到Lua;
  • 如何将函数的结果压入到Lua中(看起来和上一点重复,默认情况下是调用上一条进行压入Lua);
  • 将当做返回值的函数的参数(所有需要返回的)压入Lua;
  • 如何确定中间存放函数参数的值的类型;
  • 从Lua中提取函数的参数;
  • 将中间存放的函数的参数的值打扮成函数需要的实参;

发现没有,关键的一条,函数的调用居然没有支持自定义。

说了这么多,我们先来瞄一眼改装后的打包过程大概是个什么样子:

	lua_register(L, "h", (
xLB_CFunc::b<decltype(&h), // type of function
&h, // pointer of function
0, // count of default parameters for function
xLB_dfer, // setter for default parameters for function
xLB_idxer<>, // index of parameters for return
xLB_pper, // how each value pushed into Lua
xLB_rner, // how the result of function pushed into Lua
xLB_pter, // how those parameters after function calling pushed into Lua
My_vter, // decide what type of value for saving the function parameters
My_lver, // how the value load from Lua
xLB_vper // make values as function's parameters
>()));

感觉象不象一怪物,只是绑定一个小小的函数,居然要写这么多代码。实际上支持了默认参数,如果不做自定义,只要前面两个模板参数就可以了。当然,提供更多更简便的包装办法是必须的,得等下一篇了。

主要的C++11技术前两篇都说得差不多了,这里要提一下的是,怎么设置函数的默认参数,实际上默认参数设置的自定义支持是一个星期天才写的(新鲜)。为什么要说它呢,它和别的自定义支持有啥不同呢,是因为默认参数是值,不是类型,也不是函数,没办法做为模板参数来提供给打包模板(其实你早就知道了对不)。所以C++11提供的选择不过,听说以后的版本会支持将值和对象一类的东东做为模板参数(谁说值不能做为模板参数,象int类型的值不是可以么)。说得太不准确了,一般编译器的提示是none type一类。因为我们是要支持默认参数自定义,默认参数可是啥类型的都有,唯一的选择就是把这一过程打包成一个函数,然后这个函数就可以做为模板参数传过去了(敢不敢来个直接点的)。那么它大概长啥样呢

struct xLB_dfer {
template<class TUP, int PARAM_COUNT> struct xLB_tir {
static inline void go(TUP& tuple) {}
};
}; template<class TUP> struct xLB_dfer::xLB_tir<TUP, 0> {
static inline void go(TUP& tuple) {}
}; template<class TUP, class T, int Idx>
static inline void xLB_default_assign(TUP& tuple, const T& A) {
std::get<Idx>(tuple) = A;
} template<int BaseIdx, class TUP, class Idxer, class...T>
struct xLB_setdp {}; template<int BaseIdx, class TUP, int...Idxs, class...T>
struct xLB_setdp<BaseIdx, TUP, xLB_idxer<Idxs...>, T...> {
static inline void go(TUP& tuple, T...DA) {
xLB_each {
(xLB_default_assign<TUP, T, BaseIdx+Idxs>(tuple,DA),1)...
};
}
}; template<class TUP, class...T>
static inline void xLB_set_default_param(TUP& tuple, T...DA) {
using idxer_t = typename xLB_toidxer<T...>::type;
xLB_setdp<std::tuple_size<TUP>::value - sizeof...(T), TUP, idxer_t, T...>
::go(tuple, DA...);
}

又是一堆模板,看烦了没有,先看看怎么自定义一个设置函数

struct My_dfer : public xLB_dfer {};
template<class TUP>
struct My_dfer::xLB_tir<TUP, 1> {
static inline void go(TUP& tuple) {
//std::get<0>(tuple) = 9999;
xLB_set_default_param(tuple, 8888);
}
};

这看起来还差不多,函数过程中的那两句是相同功能的,提供xLB_set_default_param是为了方便代码编写,畅想一下,用一个宏(支持不定参数),上面的代码就会变得非常直观。

从这个设置函数的编写,可以猜到其它的自定义支持过程是怎么样的,没错,跟这个几乎是一模一样,都是从xLB提供的默认类型继承,并提供特化函数。特化类型全部是以xLB_tir命名,其执行函数的名称都叫go。

再来看两个自定义,一个是类型,另一个是从Lua中提取函数参数

struct My_vter : public xLB_vter {};
template<> struct My_vter::xLB_tir<clsA*> { using type = clsA*; }; struct My_lver : public xLB_lver {};
template<int BaseIdx, int idx, class TUP>
struct My_lver::xLB_tir<BaseIdx, idx, TUP, clsA*> {
static inline void go(lua_State* L, TUP& tuple, int top) {
if (idx+BaseIdx <= top) {
auto wrap = reinterpret_cast<xLB_ludwrap<clsA>*>(lua_touserdata(L, idx+BaseIdx));
auto obj = wrap->ptr(); assert(obj != nullptr);
std::get<idx>(tuple) = obj;
}
}
};

代码

xlb.h

#ifndef _XLB_H
#define _XLB_H #include <iostream>
#include <vector>
#include <assert.h>
#include <cstring>
#include <tuple>
#include <memory>
#include <type_traits>
using namespace std; extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
} // lua header files /*---------------------------------------------------------------------------
predeclare
-----------------------------------------------------------------------------*/
template<typename T> struct xLB_xotrait;
template<typename T> struct xLB_function;
template<typename T> struct xLB_xobase; // tir (Type Information Replenish)
/*---------------------------------------------------------------------------
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 {
T* ptr(){ return __ptr; }
T* operator->() { return __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_creatidxer
-----------------------------------------------------------------------------*/
template<int...> struct xLB_idxer{};
template<int...RPI> using xLB_rpi = xLB_idxer<RPI...>; // xLB_idxer alias template<int, class Idxer, int>
struct xLB_creatidxer; template<int I, int...Idxs, int RM>
struct xLB_creatidxer<I, xLB_idxer<Idxs...>, RM> {
using type = typename
xLB_creatidxer<I+1, xLB_idxer<Idxs..., I>, RM-1>::type;
}; template<int I, int...Idxs>
struct xLB_creatidxer<I, xLB_idxer<Idxs...>, 0> {
typedef xLB_idxer<Idxs...> type;
}; template<typename ...Types>
struct xLB_toidxer :
xLB_creatidxer<0, xLB_idxer<>, sizeof...(Types)> {}; /*---------------------------------------------------------------------------
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<class R, class ...A>
struct xLB_return_void<R (*)(A...)> {
static const bool value = std::is_void<R>::value;
}; /*---------------------------------------------------------------------------
xLB_each
-----------------------------------------------------------------------------*/
struct xLB_each{ template<class ...T> xLB_each(T...) {} }; /*---------------------------------------------------------------------------
xLB_dfer
function default parameters provider
-----------------------------------------------------------------------------*/
struct xLB_dfer {
template<class TUP, int PARAM_COUNT> struct xLB_tir {
static inline void go(TUP& tuple) {}
};
}; template<class TUP> struct xLB_dfer::xLB_tir<TUP, 0> {
static inline void go(TUP& tuple) {}
}; template<class TUP, class T, int Idx>
static inline void xLB_default_assign(TUP& tuple, const T& A) {
std::get<Idx>(tuple) = A;
} template<int BaseIdx, class TUP, class Idxer, class...T>
struct xLB_setdp {}; template<int BaseIdx, class TUP, int...Idxs, class...T>
struct xLB_setdp<BaseIdx, TUP, xLB_idxer<Idxs...>, T...> {
static inline void go(TUP& tuple, T...DA) {
xLB_each {
(xLB_default_assign<TUP, T, BaseIdx+Idxs>(tuple,DA),1)...
};
}
}; template<class TUP, class...T>
static inline void xLB_set_default_param(TUP& tuple, T...DA) {
using idxer_t = typename xLB_toidxer<T...>::type;
xLB_setdp<std::tuple_size<TUP>::value - sizeof...(T), TUP, idxer_t, T...>
::go(tuple, DA...);
} /*---------------------------------------------------------------------------
xLB_lver
-----------------------------------------------------------------------------*/
struct xLB_lver {
template<int BaseIdx, int idx, class TUP, class V> struct xLB_tir {
static inline void go(lua_State* L, TUP& tuple, int top) {
printf("Warning: xLB_lver(%s) not implemented.\n", typeid(V).name());
}
};
}; template<int BaseIdx, int idx, class TUP>
struct xLB_lver::xLB_tir<BaseIdx, idx, TUP, int> {
static inline void go(lua_State* L, TUP& tuple, int top) {
if (idx+BaseIdx <= top) {
std::get<idx>(tuple) = lua_tointeger(L, idx+BaseIdx);
}
}
}; template<int BaseIdx, int idx, class TUP>
struct xLB_lver::xLB_tir<BaseIdx, idx, TUP, double> {
static inline void go(lua_State* L, TUP& tuple, int top) {
if (idx+BaseIdx <= top) {
std::get<idx>(tuple) = lua_tonumber(L, idx+BaseIdx);
}
}
}; /*---------------------------------------------------------------------------
xLB_fver
-----------------------------------------------------------------------------*/
template<int BaseIdx, class LVER, class IDXER, class...TA>
struct xLB_fver {}; template<int BaseIdx, class LVER, int...idxs, class...TA>
struct xLB_fver<BaseIdx, LVER, xLB_idxer<idxs...>, TA...> {
using TUP = std::tuple<TA...>;
static inline void go(lua_State* L, TUP& tuple) {
xLB_each{ (LVER::template
xLB_tir<BaseIdx,idxs,TUP,TA>::go(L, tuple, lua_gettop(L)),1)... };
}
}; /*---------------------------------------------------------------------------
xLB_pper
push data(parameters of function) into lua_State
-----------------------------------------------------------------------------*/
struct xLB_pper {
template<typename T> struct xLB_tir {
static inline void go(lua_State* L, T tuple_val, int& return_count) {
lua_pushnumber(L, tuple_val); ++return_count;
}
};
}; template<> struct xLB_pper::xLB_tir<const char*> {
static inline void go(lua_State* L, const char* tuple_val, int& return_count) {
lua_pushstring(L, tuple_val); ++return_count;
}
}; template<> struct xLB_pper::xLB_tir<double> {
static inline void go(lua_State* L, double tuple_val, int& return_count) {
lua_pushnumber(L, tuple_val); ++return_count;
}
}; template<> struct xLB_pper::xLB_tir<long> {
static inline void go(lua_State* L, long tuple_val, int& return_count) {
lua_pushnumber(L, tuple_val); ++return_count;
}
}; template<> struct xLB_pper::xLB_tir<bool> {
static inline void go(lua_State* L, bool tuple_val, int& return_count) {
lua_pushnumber(L, tuple_val); ++return_count;
}
}; /*---------------------------------------------------------------------------
xLB_pter
push addition parameters of function into lua_State
-----------------------------------------------------------------------------*/
struct xLB_pter { template<class,class,class> struct xLB_tir {}; }; template<int...RPI,class...A,class PPER>
struct xLB_pter::xLB_tir<xLB_idxer<RPI...>,std::tuple<A...>,PPER> {
static inline void go(lua_State* L, std::tuple<A...>& tuple, int& return_count) {
xLB_each{ (PPER::template xLB_tir<
typename std::tuple_element<RPI, std::tuple<A...>>::type>
::go(L, std::get<RPI>(tuple), return_count), 1)...
};
}
}; /*---------------------------------------------------------------------------
xLB_rner
push result of function into lua_State
-----------------------------------------------------------------------------*/
struct xLB_rner {
template<class R, class PPER> struct xLB_tir {
static inline void go(lua_State* L, const R& result_of_function, int& return_count) {
PPER::template xLB_tir<R>::go(L, result_of_function, return_count);
}
};
}; /*---------------------------------------------------------------------------
xLB_vper
change type of value according to parameter's type for calling function
-----------------------------------------------------------------------------*/
struct xLB_vper {
template<class To, class From> struct xLB_tir {
static inline const To& go(const From& tuple_val) { return tuple_val; }
};
}; template<class T>struct xLB_vper::xLB_tir<T*, T*> {
static inline T* go(T* tuple_val) { return tuple_val; }
}; template<>struct xLB_vper::xLB_tir<int&, int> {
static inline int& go(int& tuple_val) { return tuple_val; }
}; template<>struct xLB_vper::xLB_tir<int*, int> {
static inline int* go(int& tuple_val) { return &tuple_val; }
}; /*---------------------------------------------------------------------------
xLB_vter
decide type of value for saving data come from lua_State
-----------------------------------------------------------------------------*/
struct xLB_vter {
template<class PARAM_TYPE> struct xLB_tir {
using type = PARAM_TYPE;
static_assert(std::is_pod<PARAM_TYPE>::value, "Warning: xLB_vter no implement\n");
};
}; template<class PARAM_TYPE> struct xLB_vter::xLB_tir<PARAM_TYPE&> {
using type = typename xLB_vter::xLB_tir<PARAM_TYPE>::type;
}; template<> struct xLB_vter::xLB_tir<int*> { using type = int; };
template<> struct xLB_vter::xLB_tir<double*> { using type = double; }; /*---------------------------------------------------------------------------
xLB_caler
-----------------------------------------------------------------------------*/
struct xLB_caler {
template<class FT,class,class,class...A> struct xLB_tir {};
}; template<class R, class T, class VPER, class...A, class...B, int...idxs>
struct xLB_caler::xLB_tir<R (T::*)(A...), xLB_idxer<idxs...>, VPER, B...> {
static inline R go(T* obj, R (T::*f)(A...), std::tuple<B...>& tuple) {
return (obj->*f)(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
}
}; template<class T, class VPER, class...A, class...B, int...idxs>
struct xLB_caler::xLB_tir<void (T::*)(A...), xLB_idxer<idxs...>, VPER, B...> {
static inline void go(T* obj, void (T::*f)(A...), std::tuple<B...>& tuple) {
(obj->*f)(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
}
}; template<class VPER, class...A, class...B, int...idxs>
struct xLB_caler::xLB_tir<void (*)(A...), xLB_idxer<idxs...>, VPER, B...> {
static inline void go(void (*f)(A...), std::tuple<B...>& tuple) {
f(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
}
}; template<class R, class VPER, class...A, class...B, int...idxs>
struct xLB_caler::xLB_tir<R (*)(A...), xLB_idxer<idxs...>, VPER, B...> {
static inline R go(R (*f)(A...), std::tuple<B...>& tuple) {
return f(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
}
};
/*---------------------------------------------------------------------------
xLB_adter
-----------------------------------------------------------------------------*/
template<class R, class T, class F, F f, int DFCOUNT, class DFER, class RPIdxer,
class PPER, class RNER, class PTER, class VTER, class LVER, class VPER, class...A>
int xLB_adter(lua_State* L) {
using wrap_t = xLB_ludwrap<T>;
using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
xLB_fver<2,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
::go(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_caler::template xLB_tir<F,idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
::go(obj, f, tuple);
int rcnt = 0;
RNER::template xLB_tir<R,PPER>::go(L,r,rcnt);
PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
::go(L, tuple, rcnt);
return rcnt;
} /*---------------------------------------------------------------------------
xLB_adter_void
-----------------------------------------------------------------------------*/
template<class T, class F, F f, int DFCOUNT, class DFER, class RPIdxer,
class PPER, class RNER, class PTER, class VTER, class LVER, class VPER, class...A>
int xLB_adter_void(lua_State* L) {
using wrap_t = xLB_ludwrap<T>;
using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
xLB_fver<2,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
::go(L, tuple);
auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
assert(wrap != nullptr);
auto obj = wrap->ptr(); assert(obj != nullptr);
xLB_caler::template xLB_tir<F,idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
::go(obj, f, tuple);
int rcnt = 0;
PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
::go(L, tuple, rcnt);
return rcnt;
} /*---------------------------------------------------------------------------
xLB_CFunc
-----------------------------------------------------------------------------*/
struct xLB_CFunc {
template<class F, F f, bool, int DFCOUNT, class DFER,
class RPIdxer, class PPER, class RNER,
class PTER, class VTER, class LVER, class VPER> struct xLB_tir {}; template<class FT, FT f,
int DFCOUNT=0,
class DFER=xLB_dfer,
class RPIdxer=xLB_idxer<>,
class PPER=xLB_pper,
class RNER=xLB_rner,
class PTER=xLB_pter,
class VTER=xLB_vter,
class LVER=xLB_lver,
class VPER=xLB_vper
> static inline lua_CFunction b() {
return xLB_CFunc::template xLB_tir<
FT,f,xLB_return_void<FT>::value,DFCOUNT,DFER,
RPIdxer,PPER,RNER,PTER,VTER,LVER,VPER
>::func;
}
}; template<class...A, void (*f)(A...), int DFCOUNT, class DFER,
class RPIdxer, class PPER, class RNER,
class PTER, class VTER, class LVER, class VPER
> struct xLB_CFunc::xLB_tir<void (*)(A...), f, true, DFCOUNT, DFER, RPIdxer, PPER, RNER, PTER, VTER, LVER, VPER> {
static int func(lua_State* L) {
using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
xLB_fver<1,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
::go(L, tuple);
xLB_caler::template xLB_tir<decltype(f),idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
::go(f, tuple);
int rcnt = 0;
PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
::go(L, tuple, rcnt);
return rcnt;
};
}; template<class...A, class R, R (*f)(A...), int DFCOUNT, class DFER,
class RPIdxer, class PPER, class RNER,
class PTER, class VTER, class LVER, class VPER
> struct xLB_CFunc::xLB_tir<R (*)(A...), f, false, DFCOUNT, DFER, RPIdxer, PPER, RNER, PTER, VTER, LVER, VPER> {
static int func(lua_State* L) {
using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
using idxer_t = typename xLB_toidxer<A...>::type;
tuple_t tuple;
DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
xLB_fver<1,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
::go(L, tuple);
R r = xLB_caler::template xLB_tir<decltype(f),idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
::go(f, tuple);
int rcnt = 0;
RNER::template xLB_tir<R,PPER>::go(L,r,rcnt);
PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
::go(L, tuple, rcnt);
return rcnt;
};
}; /*---------------------------------------------------------------------------
xLB_agent
-----------------------------------------------------------------------------*/
template<class Tx,Tx,bool,int,class,class,class,class,class,class,class,class>
struct xLB_agent {}; template<class Tx, class R, class ...A, R (Tx::*f)(A...), int DFCOUNT, class DFER, int...RPI,
class PPER, class RNER, class PTER, class VTER, class LVER, class VPER>
struct xLB_agent<R (Tx::*)(A...), f, false, DFCOUNT, DFER, xLB_idxer<RPI...>,
PPER,RNER,PTER,VTER,LVER,VPER> {
static inline void b(const char fn[]) {
xLB_xobase<Tx>::regfunc(fn,
xLB_adter<R, Tx, R (Tx::*)(A...), f, DFCOUNT, DFER, xLB_idxer<RPI...>,
PPER,RNER,PTER,VTER,LVER,VPER, A...>);
}
}; template<class Tx, class ...A, void (Tx::*f)(A...), int DFCOUNT, class DFER, int...RPI,
class PPER, class RNER, class PTER, class VTER, class LVER, class VPER>
struct xLB_agent<void (Tx::*)(A...), f, true, DFCOUNT, DFER, xLB_idxer<RPI...>,
PPER,RNER,PTER,VTER,LVER,VPER> {
static inline void b(const char fn[]) {
xLB_xobase<Tx>::regfunc(fn,
xLB_adter_void<Tx, void (Tx::*)(A...), f, DFCOUNT, DFER, xLB_idxer<RPI...>,
PPER,RNER,PTER,VTER,LVER,VPER, A...>);
}
}; /*---------------------------------------------------------------------------
xlb function
-----------------------------------------------------------------------------*/
#define luaL_reg luaL_Reg /** 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) {
using w_t = xLB_ludwrap<T>;
T* r = 0;
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));
if (wp) { r = wp->ptr(); if (pWp) { *pWp = wp; } }
} //else { nb_warn(true, "userdata expected"); }
return r;
} /* 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);
if (wp) { wp->~xLB_ludwrap<T>(); }
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_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_xoinitmember(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_pchars xLB_xobase<xo_t>::super_name_list=xLB_pchars(); \
template<> std::vector<luaL_reg> xLB_xobase<xo_t>::rg_meta={{nullptr,nullptr}}; \
template<> std::vector<luaL_reg> xLB_xobase<xo_t>::rg_type={{nullptr,nullptr}}; \ #define xLB_xodefineobj(xo_t) xLB_xotrait<xo_t> xLB_xo##xo_t; \ #define xLB_xodefine(xo_t) \
xLB_xoinitmember(xo_t) \
xLB_xodefineobj(xo_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);
return rc;
} /*---------------------------------------------------------------------------
xLB_xotrait
-----------------------------------------------------------------------------*/
template<typename T> struct xLB_xotrait{ static char meta[]; }; typedef std::vector<const char*> xLB_pchars;
int xLB_search(lua_State* L, const char* method_name, const xLB_pchars& nlst);
int xLB_rawsearch(lua_State* L, const char* method_name, const char* meta_name); /*---------------------------------------------------------------------------
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_pchars super_name_list;
static regs_t rg_meta;
static regs_t rg_type;
//virtual ~xLB_xobase() = delete; static inline void regfunc(const char fn[], lua_CFunction f) {
auto it = begin(rg_meta);
rg_meta.insert(it, {fn,f});
} 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;
} static 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> static void super() {
super_name_list.push_back(xLB_xotrait<SUPER_XO>::meta_name);
} template<lua_CFunction f> static void c(const char fn[]="new") {
auto it = begin(rg_type);
rg_type.insert(it, {fn,f});
} static void d() { b<xLB_gcxo<T>>("__gc"); } template<typename xLB_method<T>::type f> static void b(const char fn[]) {
regfunc(fn, xLB_xomethod<T, f>);
} template<lua_CFunction f> static void b(const char fn[]) {
regfunc(fn, f);
} template<class FT, FT f,
int DFCOUNT = 0,
class DFER=xLB_dfer,
class RPIs=xLB_idxer<>,
class PPER=xLB_pper,
class RNER=xLB_rner,
class PTER=xLB_pter,
class VTER=xLB_vter,
class LVER=xLB_lver,
class VPER=xLB_vper>
static void bx(const char fn[]) {
xLB_agent<FT, f, xLB_return_void<FT>::value, DFCOUNT, DFER, RPIs,
PPER,RNER,PTER,VTER,LVER,VPER
>::b(fn);
} static void reg(lua_State* L, const char* ns = nullptr) {
if (1 < rg_meta.size()) { newxometatable(L); }
if (1 < rg_type.size()) {
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);
}
}
}
}; // end of xLB_xobase /*---------------------------------------------------------------------------
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>

/*---------------------------------------------------------------------------
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,
const char* method_name, const xLB_pchars& 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,
const char* method_name, const char* 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)
//nb_warn(inew, "xLB-Error: %d %s", inew, LibName);
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);
}
*/

测试的一段代码

xlbinder.h

#ifndef _XLBINDER_H
#define _XLBINDER_H #include <ns/xlb.h>
#include <type_traits> struct clsB {
void b() { printf("base class clsB::b() method called\n"); }
}; struct clsA : public clsB {
int Add(int a, int& b);
int Del(int* a);
int Modify(int& a);
void NoReturn(int a);
void Complex(clsA* pa);
int x = 999;
}; // end of clsA xLB_xodeclare(clsB) {
xLB_xotrait() {
bx<decltype(&clsB::b), &clsB::b>("b");
}
}; struct My_vter : public xLB_vter {};
template<> struct My_vter::xLB_tir<clsA*> { using type = clsA*; }; struct My_lver : public xLB_lver {};
template<int BaseIdx, int idx, class TUP>
struct My_lver::xLB_tir<BaseIdx, idx, TUP, clsA*> {
static inline void go(lua_State* L, TUP& tuple, int top) {
if (idx+BaseIdx <= top) {
auto wrap = reinterpret_cast<xLB_ludwrap<clsA>*>(lua_touserdata(L, idx+BaseIdx));
auto obj = wrap->ptr(); assert(obj != nullptr);
std::get<idx>(tuple) = obj;
}
}
}; struct My_dfer : public xLB_dfer {};
template<class TUP>
struct My_dfer::xLB_tir<TUP, 1> {
static inline void go(TUP& tuple) {
//std::get<0>(tuple) = 9999;
xLB_set_default_param(tuple, 8888);
}
}; xLB_xodeclare(clsA) {
xLB_xotrait() {
super<clsB>();
bx<decltype(&clsA::Add), &clsA::Add, 0, xLB_dfer, xLB_idxer<1,0>>("Add");
bx<decltype(&clsA::NoReturn), &clsA::NoReturn, 1, My_dfer, xLB_idxer<0>>("NoReturn");
bx<decltype(&clsA::Complex), &clsA::Complex, 0, xLB_dfer, xLB_idxer<>,
xLB_pper,
xLB_rner,
xLB_pter,
My_vter, //xLB_vter,
My_lver, //xLB_lver,
xLB_vper
>("Complex");
}
}; struct mytype {
int a;
}; void foo(int a);
int g(int a);
int h(clsA* a); #endif

xlbinder.cpp

#include "xlbinder.h"

//----------------------------------------------------------------------
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 clsA::Complex(clsA* pa) { printf("Complex %d\n", pa->x); } //----------------------------------------------------------------------
void foo(int a) { printf("foo called: %d\n", a); }
int g(int a) { printf("g called: %d\n", a); return a+2; }
int h(clsA* a) { printf("h called: %d\n", a->x); return 0; } //----------------------------------------------------------------------
xLB_xodefine(clsA);
xLB_xodefine(clsB);
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
int main() {
std::cout << "xLB test ... \n";
auto L = luaL_newstate();
luaL_openlibs(L);
xLB_bindxo<clsB>(L);
xLB_bindxo<clsA>(L);
clsA obj;
obj.x = 99;
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:Complex(obj));");
luaL_dostring(L, "print(obj:Add(99,2));"); luaL_dostring(L, "x = obj:NoReturn(8); ");
luaL_dostring(L, "print('obj:NoReturn(8)=' .. tostring(x));");
luaL_dostring(L, "x = obj:NoReturn(); ");
luaL_dostring(L, "print('obj:NoReturn(default_param)=' .. tostring(x));"); //---
lua_register(L, "foo", (xLB_CFunc::b<decltype(&foo), &foo, 1, My_dfer>()));
luaL_dostring(L, "x = foo(1901);");
luaL_dostring(L, "print('foo(1901)=' .. tostring(x));");
luaL_dostring(L, "x = foo();");
luaL_dostring(L, "print('foo(default_param)=' .. tostring(x));"); lua_register(L, "g", (xLB_CFunc::b<decltype(&g), &g, 0, xLB_dfer, xLB_idxer<0>>()));
luaL_dostring(L, "print(g(1999));"); lua_register(L, "h", (
xLB_CFunc::b<decltype(&h), // type of function
&h, // pointer of function
0, // count of default parameters for function
xLB_dfer, // setter for default parameters for function
xLB_idxer<>, // index of parameters for return
xLB_pper, // how each value pushed into Lua
xLB_rner, // how the result of function pushed into Lua
xLB_pter, // how those parameters after function calling pushed into Lua
My_vter, // decide what type of value for saving the function parameters
My_lver, // how the value load from Lua
xLB_vper // make values as function's parameters
>()));
luaL_dostring(L, "h(obj);");
luaL_dostring(L, "obj:b()"); // call base class method lua_close(L);
printf("}\n");
return 0;
}

输出结果:

xLB test ...
Lua{
getmetatable(obj)={
Add=function: 004094D0
__index=function: 004096A0
Complex=function: 00409214
NoReturn=function: 00409300
}
Complex 99 clsA::Add(99,2):101 called
224 99 125
obj:NoReturn called: 24
obj:NoReturn(8)=8
obj:NoReturn called: 26664
obj:NoReturn(default_param)=8888
foo called: 1901
foo(1901)=nil
foo called: 8888
foo(default_param)=nil
g called: 1999
2001 1999
h called: 99
base class clsB::b() method called
}
05-11 19:29