在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
书接上一回,说到要继续丰富对类型的处理。那么如何才能做到呢,应该是要支持自定义的,所以这一回要讲的就是在前面的基础上,增加支持自定义部分,其中包含以下几个部分
发现没有,关键的一条,函数的调用居然没有支持自定义。 说了这么多,我们先来瞄一眼改装后的打包过程大概是个什么样子:
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提供的默认类型继承,并提供特化函数。特化类型全部是以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__
#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
#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 }
|
请发表评论