• 20140102-lua binder另一只轮子的雏形


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

    • 函数的默认参数设置,包括有几个默认参数和如何设置这些默认参数;
    • 可以做为返回值的参数下标(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.
    ", 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
    "); 
    	};
    };
    
    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
    "); }
    };
    
    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
    ", a,b,a+b);
    	b+=123;
    	return a+b; 
    }
    int clsA::Del(int* a) { printf("obj:Del called: %d
    ", *a); return *a = 2; };
    int clsA::Modify(int& a) { return a*=2; }
    void clsA::NoReturn(int a) { printf("obj:NoReturn called: %d
    ", a*3); }
    void clsA::Complex(clsA* pa) { printf("Complex %d
    ", pa->x); }
    
    //----------------------------------------------------------------------
    void foo(int a) { printf("foo called: %d
    ", a); }
    int g(int a) { printf("g called: %d
    ", a); return a+2; }
    int h(clsA* a) { printf("h called: %d
    ", a->x); return 0; }
    
    
    //----------------------------------------------------------------------
    xLB_xodefine(clsA);
    xLB_xodefine(clsB);
    //----------------------------------------------------------------------------
    
    
    //----------------------------------------------------------------------------
    int main() {
    	std::cout << "xLB test ... 
    ";
    	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("}
    ");
    	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
    }



  • 相关阅读:
    ajax 发送 json 数组
    h5拖动总结
    TypeScript 学习
    java程序员面试经历(不忘初心,永不放弃,方得始终)。
    mysql统计天、周、月、季度、半年、年
    C++错误unresolved external symbol _WinMain@16
    记mysql条件分支语句CASE WHEN THEN ELSE END的使用
    freemarker数据格式化问题(即数值超过三位后自动添加逗号问题)
    tomcat启动内存溢出三种解决方案:java.lang.OutOfMemoryError:PermGen space解决办法
    Spring事务异常回滚,捕获异常不抛出就不会回滚
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3503165.html
Copyright © 2020-2023  润新知