20130721-lua binder另一只轮子的雏形

5 篇文章 0 订阅
4 篇文章 0 订阅

利用c++11新特性来实现一个lua binder,这一次比上次写的超级雏形要完善一些,基本上可以在练习时使用了,要真正投入到项目中,还得继续丰富对类型的处理和调整,待下一篇再写。

上一篇使用了由侯选模板拆分函数参数的写法,这次使用的是variadic template的另一种用法,由待调用的函数(只做类型的分析,无实际功能)和参数包共同完成函数参数的拆分。

相对一些老早就出来的库,这个是非常简陋的。为什么又要多造一个车轮更多的是出于学习的目的。轻装出发,我们用一个包装函数使它可以在Lua中被调用的例子,选择普通的函数,如

int add(int a, int b) {
  return a+b;
}

那么手工写一个包装函数大致如下

int lf_add(lua_State* L) {
  int a = lua_tonumber(L, 1);
  int b = lua_tonumber(L, 2);
  int c = a+b;
  lua_pushnumber(L, c);
  return 1;
}

我们的任务就是完成对这个函数的一般化,就是写一个(应当是一些)模板xLB_adapter,然后传入函数类型add,由编译器生成一个生成包装的函数,这样在Lua环境中就可以调用到它了。

xLB_adapter需要完成的功能大概可分成三个部分:

  • 1.把参数从lua_State*中取出来(如果有的话)
  • 2.调用C++中的函数,如果有返回值,保存之
  • 3.如果返回值,把它压回lua_State*中,并最终返回压入返回值的个数

基本的解决思路是用variadic template来完成,中间的参数存放放到tuple中。


  • 任务1用这个完成

xLB_getter<2, idxer_t,typename xLB_vt<A>::type...>::get(L, tuple);

其中idxer_t是根据函数的参数个数(有些函数是没办法确定参数个数的,这个留到以后再干)生成的一个类型,这个类型中啥都没有,就是个序列(不是值,是类型里的信息),

template<int...> struct xLB_idxer{}; 

就是这个东东,序列包含中int...中(生成这样的序列办法很多,从网上抄了一个)。有了这个序列之后,我们就能一个一个的从lua_State*中把参数提取出来(序列可以做为Lua栈的下标使用)。

这里的2是什么东东(也许你不用管它,它是做为tuple中的函数参数下标与Lua栈下标的一个对准值来用的)。

xLB_vt<A>::type又是个什么东东,用它来把函数的参数类型转化从实际可从lua_State*提取的类型,如函数有一个参数,它的类型是int*,Lua中是没这东东的,我们要把它变成大概是int这样的类型(为什么是大概呢,这个根据需要来,当然对于此次的学习,我只是把它转成int,至于是如何转的,写一堆特化的类模型应该就可以了)。xLB_getter大概象下面这个样子,可以看出来,它啥也不做,除了一些类型的分析,然后就是调用一个xLB_each的东东。

template<int BaseIdx, int...idxs, class...A>
  struct xLB_getter<BaseIdx, xLB_idxer<idxs...>, A...> {
    static inline void get(lua_State* L, std::tuple<A...>& tuple) {
      xLB_each{ (xLB_get<BaseIdx, idxs,std::tuple<A...>,A>(L, tuple),1)... };
    }
  };

这个xLB_each也是什么也不做,只是让编译器知道,传过来的到xLB_each构造函数的实参应该是一堆参数(0到N,我也不知道N可以是多少)。象上面那样使用xLB_each实际就是variadic template的另一种写法,与上次练习相比,这种写法更简洁,但也更少的可控,没头没尾。(这里的xLB_each为什么要写成类模型呢? 也可以函数模板的,但你会发现,这次练习中使用的大多数是类模型,感觉它操作起类型来更加有威力,如果那一天发现恰恰相反,OMG)

struct xLB_each{ template<class ...T> xLB_each(T...) {} };


  • 任务2用这个完成

R r = xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>::call(obj, f, tuple);

这是有返回值的(如果没有返回值呢,我也不知道怎么办,我是通过写了另一个模板来解决没有返回值的问题。如果你有更好的办法,麻烦告诉我QQ158989725,希望你有用QQ,并喜欢用它)。xLB_call大致的实现如

template<class R, class T, class...A, class...B, int...idxs> 
  struct xLB_call<R (T::*)(A...), xLB_idxer<idxs...>, B...> {
    static inline R call(T* obj, R (T::*f)(A...), std::tuple<B...>& tuple) {
      return (obj->*f)(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
    }
  };

你会发现不对劲,没错,这里写的是包装C++类的函数调用,有个obj。这里要做两件事,把参数(中间参数,也许被弄个面目全非了,也许是原样不动)从tuple中取出来,转成能够做为被包装函数的实参的类型(把类型又改回去,多折腾)。最后是调用了被包装的函数。


  • 任务3用这个完成

xLB_return_param<RPIdxer,typename xLB_vt<A>::type...>::return_param(L, tuple, return_count);

xLB_vt前面已经讲过,这里多了一个叫RPIdxer,就是返回哪些参数到Lua中(没错,Lua是支持多参数返回的),那RPIdxer是个什么东东呢,它实际是前面说过的序列xLB_idxer,不过它的序列是由你来决定的,不是根据函数参数来决定的,比如你想返回10参数中的第5个(这个比较好只,已经写出来了,比如你想返回一个固定值还是什么其它的,那将是一个很好的家庭作业)。对了,还有一个return_count,如果有返回就修改它(+1),最终将把它作为包装函数的返回值返回给Lua。

template<int...RPI, class...A>   
    struct xLB_return_param<xLB_idxer<RPI...>,A...> {  
        static inline void return_param(lua_State* L,   
                const std::tuple<A...>& tuple, int& return_count) {  
            xLB_each{ (xLB_pusher(L, std::get<RPI>(tuple), return_count), 1)... };  
        }  
    };  


以下是xlb源代码和一个例子(仔细瞧瞧,有问题,好像R没做类型转换)。

xlb.h

#ifndef _XLB_H
#define _XLB_H

// rpc object used in lua
//#include <ns/nr.h>
#include <nbbase.h>
using namespace loon;

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
} // lua header files


/*---------------------------------------------------------------------------
xLB_ludwrap : light user data wrapp as user data
-----------------------------------------------------------------------------*/
/* @struct xLB_ludwrap
 * This template used to wrapper lightuserdata as userdata, and then we can
 * set metatable on its. It's instance life managered by C++ not by Lua. */
template<typename T> struct xLB_ludwrap {
	//operator T*(){ return __ptr; }
	T* ptr(){ return __ptr; }
	T* operator->() { return __ptr; }
	//xLB_ludwrap& operator=(T* ptr){ __ptr = ptr; }
	//bool operator==(T* ptr){ return __ptr == ptr; }
	//bool operator==(const xLB_ludwrap<T>& r){ return __ptr == r.__ptr; }
	xLB_ludwrap(T* ptr, bool del=false) : __ptr(ptr), __del(del) {}
	virtual ~xLB_ludwrap(){ if (__del) { delete __ptr; } }
protected:
	T* __ptr; /**< real object */
	bool __del; /**< delete __ptr when xLB_ludwrap was release */
}; // end of xLB_ludwrap


/*---------------------------------------------------------------------------
xLB_pusher
-----------------------------------------------------------------------------*/
template<typename T> 
	inline void xLB_pusher(lua_State* L, T r, int& return_count) {
		lua_pushnumber(L, r); ++return_count; 
	}

template<typename R, typename T> 
	inline void xLB_pusher(lua_State* L, R& r, int& return_count) {}

template<typename T> 
	inline void xLB_pusher(lua_State* L, T* r, int& return_count) { 
		lua_pushvalue(L, 1); ++return_count; 
	}

template<typename T> 
	inline void xLB_pusher(lua_State* L, char* r, int& return_count) { 
		lua_pushstring(L, r); ++return_count; 
	}

template<typename T> 
	inline void xLB_pusher(lua_State* L, double r, int& return_count) { 
		lua_pushnumber(L, r); ++return_count; 
	}

template<typename T> 
	inline void xLB_pusher(lua_State* L, long r, int& return_count) { 
		lua_pushnumber(L, r); ++return_count; 
	}

template<typename T> 
	inline void xLB_pusher(lua_State* L, bool r, int& return_count) { 
		lua_pushboolean(L, r); ++return_count; 
	}

/*---------------------------------------------------------------------------
xLB_make_indexes_impl
-----------------------------------------------------------------------------*/
template<int...> struct xLB_idxer{}; 
template<int...RPI> using xLB_rpi = xLB_idxer<RPI...>; // xLB_idxer alias

template<int I, class IndexTuple, class... Types> 
	struct xLB_make_indexes_impl; 

template<int I, int... Indexes, class T, class ... Types> 
	struct xLB_make_indexes_impl<I, xLB_idxer<Indexes...>, T, Types...> { 
		typedef typename xLB_make_indexes_impl
			<I + 1, xLB_idxer<Indexes..., I>, Types...>::type type; 
	}; // end of xLB_make_indexes_impl

template<int I, int... Indexes> 
	struct xLB_make_indexes_impl<I, xLB_idxer<Indexes...> > { 
			typedef xLB_idxer<Indexes...> type; 
	}; // end of xLB_make_indexes_impl

template<typename ... Types> 
	struct xLB_toidxer : 
		xLB_make_indexes_impl<0, xLB_idxer<>, Types...> {}; 

/*---------------------------------------------------------------------------
xLB_get param from lua_State
-----------------------------------------------------------------------------*/
template<int BaseIdx, int idx, class TUP, class V>
	struct xLB_get_impl {
		static inline void go(lua_State* L, TUP& tuple) { }
	};

template<int BaseIdx, int idx, class TUP>
	struct xLB_get_impl<BaseIdx, idx, TUP, int> {
		static inline void go(lua_State* L, TUP& tuple) {
			std::get<idx>(tuple) = lua_tointeger(L, idx+BaseIdx);
		}
	};

template<int BaseIdx, int idx, class TUP>
	struct xLB_get_impl<BaseIdx, idx, TUP, double> {
		static inline void go(lua_State* L, TUP& tuple) {
			std::get<idx>(tuple) = lua_tonumber(L, idx+BaseIdx);
		}
	};

/*
template<class TUP, class T>
struct xLB_get_impl<0, TUP, T*> {
	static void go(lua_State* L, TUP& tuple) {
		std::get<0>(tuple) = reinterpret_cast<T*>(lua_touserdata(L, 2));
	}
};
*/

template<int BaseIdx, int idx, class TUP, class V>
	inline void xLB_get(lua_State* L, TUP& tuple) {
		xLB_get_impl<BaseIdx, idx, TUP, V>::go(L, tuple);
		// in R (T::*)(A...)
		//<0,1,...,n> 0=param1,lua idx=2; lua idx=1 is obj
		// in T (*)(A...)
		//<0,1,...,n> 0=param1,lua idx=1
	}

/*---------------------------------------------------------------------------
xLB_getter get arguments from lua_State and save in tuple
-----------------------------------------------------------------------------*/
struct xLB_each{ template<class ...T> xLB_each(T...) {} };
/*
template<class ...A, int ...idxs> inline void 
xLB_getter(lua_State* L, std::tuple<A...>& tuple, xLB_idxer<idxs...>&) {
	xLB_each{ (xLB_get<idxs,std::tuple<A...>,A>(L, tuple),1)... };
}
*/

template<int BaseIdx, class IDXER, class...PARAM>
	struct xLB_getter {};

template<int BaseIdx, int...idxs, class...A>
	struct xLB_getter<BaseIdx, xLB_idxer<idxs...>, A...> {
		static inline void get(lua_State* L, std::tuple<A...>& tuple) {
			xLB_each{ (xLB_get<BaseIdx, idxs,std::tuple<A...>,A>(L, tuple),1)... };
		}
	};

/*---------------------------------------------------------------------------
xLB_gv1
-----------------------------------------------------------------------------*/
//template<class T1, class T2>inline T1 xLB_gv1(const T2& v) { }
//template<class T1>inline T1& xLB_gv1(T1& v) { return v; }
//template<class T1> inline T1* xLB_gv1(T1& v) { return &v; }
//int* xLB_gv1(int& v) { return &v; }
template<class To, class From> struct xLB_gv1 { };
template<class T1> struct xLB_gv1<T1, T1> { 
		inline static T1& val(T1& v) { return v; } 
	};
template<> struct xLB_gv1<int*, int> { 
		inline static int* val(int& v) { return &v; } 
	};
template<> struct xLB_gv1<int&, int> { 
		inline static int& val(int& v) { return v; } 
	};

/*---------------------------------------------------------------------------
xLB_call call obj method, obj=tuple[0] and arguments=tuple[1...]
-----------------------------------------------------------------------------*/
	//auto wrap = reinterpret_cast<T*>(std::get<0>(tuple));
		//auto obj = wrap->ptr();
		//return (obj->*f)(std::get<idxs>(tuple)...);
	//auto wrap = reinterpret_cast<T*>(std::get<0>(tuple));
	//(wrap->ptr()->*f)(std::get<idxs>(tuple)...);
/*
template<class R, class T, class ...B, class F, class ...A, int ...idxs> inline R 
xLB_call(F f, T* obj, std::tuple<A...>& tuple, xLB_idxer<idxs...>&) {
	if (obj) {
		return (obj->*f)(xLB_gv1<B,A>::val(std::get<idxs>(tuple))...);
	} else {
		nb_warn(true, "obj expected but nil");
		return R{};
	}
}
*/
template<class FT, class, class...A> struct xLB_call{};

template<class R, class T, class...A, class...B, int...idxs> 
	struct xLB_call<R (T::*)(A...), xLB_idxer<idxs...>, B...> {
		static inline R call(T* obj, R (T::*f)(A...), std::tuple<B...>& tuple) {
			return (obj->*f)(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
		}
	};

template<class T, class...A, class...B, int...idxs> 
	struct xLB_call<void (T::*)(A...), xLB_idxer<idxs...>, B...> {
		static inline void call(T* obj, void (T::*f)(A...), std::tuple<B...>& tuple) {
			(obj->*f)(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
		}
	};

template<class...A, class...B, int...idxs>
	struct xLB_call<void (*)(A...), xLB_idxer<idxs...>, B...> {
		static inline void call(void (*f)(A...), std::tuple<B...>& tuple) {
			f(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
		}
	};

template<class...A, class...B, class R, int...idxs>
	struct xLB_call<R (*)(A...), xLB_idxer<idxs...>, B...> {
		static inline R call(R (*f)(A...), std::tuple<B...>& tuple) {
			return f(xLB_gv1<A,B>::val(std::get<idxs>(tuple))...);
		}
	};
/*
template<class T, class ...B, class F, class ...A, int ...idxs> inline void 
xLB_caller_void(F f, T* obj, std::tuple<A...>& tuple, xLB_idxer<idxs...>&) {
	assert(obj!=nullptr);
	(obj->*f)(xLB_gv1<B,A>::val(std::get<idxs>(tuple))...);
}
*/


/*
int f(int i) { std::cout << "f(int) " << i << std::endl; return i*2; }
double f(double d) { std::cout << "f(double) " << d << std::endl; return d*2; }

template<class ... A>inline void pass(A&&...) {}

template<class ... A>inline void expand(A&&...a) {
	pass(f(a)...);
}

template<class ... A>inline void expand2(A&&...a) {
	pass2{(f(a),1)...};
}

struct pass2{
	template<typename ...T> pass2(T...) {}
};

template<class TUPLE>
struct class_operator {
	template<int j>
	void get(int i) { std::get<j>(tuple) = i;  std::cout << j << " class_operator(int) " << i << std::endl; }
	template<int j>
	void get(double d) { std::get<j>(tuple) = d; std::cout << j << " class_operator(doule) " << d << std::endl; }
	TUPLE tuple;
	unsigned index = 0;
};

template<class ...A, int ...idxs>
void pass3(class_operator<std::tuple<A...>>& class_, index_tuple<idxs...>& idx, A&...a) {
		//pass2{(std::get<idxs>(class_.tuple),1)...};
		pass2{(class_.get<idxs>(a),1)...};
}

template<class ...A>inline void expand3(A&&...a) {
	typedef std::tuple<A...> test_tuple;
	class_operator<test_tuple> class_;
	class_.index = sizeof...(A);
	typename make_indexes<A...>::type indexer;
	//pass2{(class_.get<0>(a),1)...};
	pass3(class_, indexer, a...);
	std::cout << std::get<0>(class_.tuple) << std::endl;
}

*/

template<typename T> struct xLB_xotrait;
template<typename T> struct xLB_function;
template<typename T> struct xLB_xobase;

#define luaL_reg luaL_Reg
/*---------------------------------------------------------------------------
xlb function
-----------------------------------------------------------------------------*/
/** This function create metatable with lua api and set __index and metatable 
 * to itself and make it have key weak feature. */
void xLB_newmetatable(lua_State* L, const char* LibName, luaL_Reg* Lreg);

/** This function set metatable named LibName to userdata at top of stack. */
void xLB_userdata(lua_State* L, const char* LibName, lua_Number N = 0);


/*---------------------------------------------------------------------------
lua userdata and C++ object
-----------------------------------------------------------------------------*/
/** if the object specify by index is userdata then
 * 1. if it is instance of type xLB_ludwrap<T> then get T* address from it;
 * 2. if it is derived from T* then get T* from userdata;
 * otherwise return nullptr; */
template<typename T, const char meta[]>
T* xLB_getuserdata(lua_State* L, int index, xLB_ludwrap<T>** pWp = 0) {
	typedef xLB_ludwrap<T> w_t;
	T* r = 0;
	//nb_warn(true, "%d-%d", lua_isuserdata(L, index), index);
	if (lua_isuserdata(L, index)) {
		//auto wp = reinterpret_cast<w_t*>(luaL_checkudata(L, index, meta));
		auto wp = reinterpret_cast<w_t*>(lua_touserdata(L, index));
		//auto wp = dynamic_cast<w_t*>(lua_touserdata(L, index));
		//nb_warn(true, "%x", wp);
		if (wp) { r = wp->ptr(); if (pWp) { *pWp = wp; } }
		//else { r = lua_touserdata(L, index); }
		//else { nb_warn(true, "not wrap"); }
	} //else { nb_warn(true, "userdata expected"); }
	//nb_warn(true, "%x", r);
	return r;
}

/*
template<typename T, const char meta[]>
T* xLB_newuserdata(lua_State* L) {
	auto place = (T*)(lua_newuserdata(L, sizeof(T)));
	xLB_userdata(L, meta, 0);
	return place;
}

template<typename T, const char meta[]>
void xLB_wraplud(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj);
	xLB_userdata(L, meta, 0);
}
*/

/* Wrap xo as Lua ud, and Lua do not charge object's life. */
template<typename T>
void xLB_wrapxo(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj/*,false*/);
	xLB_userdata(L, xLB_xotrait<T>::meta_name, 0);
}

template<typename T, const char meta[]>
void xLB_objasud(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj, true);
	xLB_userdata(L, meta, 0);
}

/* Wrap xo as Lua ud, means Lua charge object's life. */
template<typename T>
void xLB_xoasud(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	w_t* place = static_cast<w_t*>(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj, true);
	xLB_userdata(L, xLB_xotrait<T>::meta_name, 0);
}

template<typename T, const char meta[]>
int xLB_gcobj(lua_State* L) {
	xLB_ludwrap<T>* wp = 0;
	xLB_getuserdata<T, meta>(L, 1, &wp);
	if (wp) { wp->~xLB_ludwrap<T>();}
	return 0;
}

template<typename T, typename...A>
T* xLB_newxo(lua_State* L, A...arg_metas) {
	T* pobj = new T(arg_metas...);
	xLB_objasud<T, xLB_xotrait<T>::meta_name>(L, pobj);
	return pobj;
}

template<typename T>
int xLB_gcxo(lua_State* L) {
	xLB_ludwrap<T>* wp = nullptr;
	xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, 1, &wp);
	//nb_warn(true, xLB_xotrait<T>::meta_name);
	if (wp) { wp->~xLB_ludwrap<T>(); }
	//nb_warn(true, "...>");
	return 0;
}

/*---------------------------------------------------------------------------
xLB binder
-----------------------------------------------------------------------------*/
template<typename T>
	unique_ptr<xLB_xotrait<T>> xLB_newxobinder() {
		return unique_ptr<xLB_xotrait<T>>(new xLB_xotrait<T>());
	}

template<typename T>
	void xLB_bindxo(lua_State* L, const char* ns=nullptr) {
		xLB_xotrait<T>().reg(L, ns);
	}

template<typename T>
	void xLB_regxo(lua_State* L, xLB_xotrait<T>* xo) { xo->reg(L); }

template<typename T>
	void xLB_xoglobal(lua_State* L, T* obj, const char* name) {
		xLB_wrapxo(L, obj);
		lua_setglobal(L, name);
	}

/*---------------------------------------------------------------------------
xLB ns table
-----------------------------------------------------------------------------*/
#define xLB_pushtable(L, tbl, name, ns) tbl().reg(L, name, ns);
void xLB_newnstable(lua_State* L, const char* name, const char* ns);
void xLB_newnstable(lua_State* L, const char* tn, int index);
//void xLB_getnstable(lua_State* L, const char* name, const char* ns);

/*---------------------------------------------------------------------------
xo macro
-----------------------------------------------------------------------------*/
#define xLB_xodefine(xo_t) \
template<> const char xLB_xobase<xo_t>::meta_name[]="xLB_"#xo_t; \
template<> const char xLB_xobase<xo_t>::type_name[]=#xo_t; \
template<> xLB_namelist_t xLB_xobase<xo_t>::super_name_list=xLB_namelist_t();

#define xLB_xodeclare(xo_t) \
template<> struct xLB_xotrait<xo_t> : public xLB_xobase<xo_t>

/*---------------------------------------------------------------------------
xLB_method
-----------------------------------------------------------------------------*/
template<typename T>struct xLB_method {
	using type =int (*)(lua_State*, T*);
};

template<typename R, typename T, typename... A>
struct xLB_method<R (T::*)(A...) > {
	using type = R(T::*)(A...);
};

template<typename R, typename T, typename... A>
struct xLB_method<R (T::*)(A...) const > {
	using type = R(T::*)(A...) const;
};

template<typename T>
T* xLB_getxo(lua_State* L, int index) {
	return xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, index);
}

template<typename T, typename xLB_method<T>::type f>
int xLB_xomethod(lua_State* L) {
	int rc = 0;
	T* obj = xLB_getxo<T>(L, 1);
	if (obj) rc = f(L, obj);
	//else nb_warn(true, "%s not registered", xLB_xotrait<T>::meta_name);
	return rc;
}

/*---------------------------------------------------------------------------
xLB_vt
-----------------------------------------------------------------------------*/
template<class Tx>struct xLB_vt { using type = Tx; };
template<class Tx>struct xLB_vt<Tx&> { using type = typename xLB_vt<Tx>::type; };
template<>struct xLB_vt<int*> { using type = int; };

	//using tuple_t = std::tuple<wrap_t*, typename std::remove_reference<A>::type...>;
	//
	//using tuple_t = std::tuple<wrap_t*, typename xLB_vt<A>::type...>;
	//using idxer_t = typename xLB_toidxer<wrap_t*, A...>::type;
	
	//using tuple_t = std::tuple<wrap_t*, typename std::remove_reference<A>::type...>;
	//
	//using tuple_t = std::tuple<wrap_t*, typename xLB_vt<A>::type...>;
	//using idxer_t = typename xLB_toidxer<wrap_t*, A...>::type;
/*---------------------------------------------------------------------------
xLB_return_param
-----------------------------------------------------------------------------*/
/*
template<int...RPI, class...A>
	void xLB_return_param(lua_State* L, 
			const std::tuple<A...> &tuple, xLB_idxer<RPI...>&, int& return_count) {
		xLB_each{ (xLB_pusher(L, std::get<RPI>(tuple), return_count),1)... };
	}
*/
template<class, class...> struct xLB_return_param {};

template<int...RPI, class...A> 
	struct xLB_return_param<xLB_idxer<RPI...>,A...> {
		static inline void return_param(lua_State* L, 
				const std::tuple<A...>& tuple, int& return_count) {
			xLB_each{ (xLB_pusher(L, std::get<RPI>(tuple), return_count), 1)... };
		}
	};
	//R r = xLB_call<R,T,A...>(f, obj, tuple, indexer);
	//xLB_caller_void<T,A...>(f, obj, tuple, indexer);
	//idxer_t indexer;
	//idxer_t indexer;
	//RPIdxer rpi_idxer;
	//xLB_return_param(L, tuple, rpi_idxer, return_count);
	//RPIdxer rpi_idxer;
	//xLB_return_param(L, tuple, rpi_idxer, return_count);
/*---------------------------------------------------------------------------
xLB_adapter
-----------------------------------------------------------------------------*/
template<class R, class T, class F, F f, class RPIdxer, class...A>
int xLB_adapter(lua_State* L) {
	using wrap_t = xLB_ludwrap<T>;
	using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
	using idxer_t = typename xLB_toidxer<A...>::type;
	tuple_t tuple;
	xLB_getter<2, idxer_t,typename xLB_vt<A>::type...>
		::get(L, tuple);
	auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
	assert(wrap != nullptr);
	auto obj = wrap->ptr(); assert(obj != nullptr);
	R r = xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
		::call(obj, f, tuple);
	int return_count = 0;
	xLB_pusher(L, r, return_count);
	xLB_return_param<RPIdxer,typename xLB_vt<A>::type...>
		::return_param(L, tuple, return_count);
	return return_count;
}

template<class T, class F, F f, class RPIdxer, class...A>
int xLB_adapter_void(lua_State* L) {
	using wrap_t = xLB_ludwrap<T>;
	using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
	using idxer_t = typename xLB_toidxer<A...>::type;
	tuple_t tuple;
	xLB_getter<2, idxer_t,typename xLB_vt<A>::type...>
		::get(L, tuple);
	auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
	assert(wrap != nullptr);
	auto obj = wrap->ptr(); assert(obj != nullptr);
	xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
		::call(obj, f, tuple);
	int return_count = 0;
	xLB_return_param<RPIdxer,typename xLB_vt<A>::type...>
		::return_param(L, tuple, return_count);
	return return_count;
}

template<class FT, FT f, int...> struct xLB_CFunc {};

template<class...A, void (*f)(A...), int...RPI>
	struct xLB_CFunc<void (*)(A...), f, RPI...> {
		static int adapter(lua_State* L) {
			using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
			using idxer_t = typename xLB_toidxer<A...>::type;
			tuple_t tuple;
			xLB_getter<1, idxer_t,typename xLB_vt<A>::type...>
				::get(L, tuple);
			xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
				::call(f, tuple);
			int return_count = 0;
			xLB_return_param<xLB_idxer<RPI...>,typename xLB_vt<A>::type...>
				::return_param(L, tuple, return_count);
			return return_count;
		}
	};

template<class...A, class R, R (*f)(A...), int...RPI>
	struct xLB_CFunc<R (*)(A...), f, RPI...> {
		static int adapter(lua_State* L) {
			using tuple_t = std::tuple<typename xLB_vt<A>::type...>;
			using idxer_t = typename xLB_toidxer<A...>::type;
			tuple_t tuple;
			xLB_getter<1, idxer_t,typename xLB_vt<A>::type...>
				::get(L, tuple);
			R r = xLB_call<decltype(f),idxer_t,typename xLB_vt<A>::type...>
				::call(f, tuple);
			int return_count = 0;
			xLB_pusher(L, r, return_count);
			xLB_return_param<xLB_idxer<RPI...>,typename xLB_vt<A>::type...>
				::return_param(L, tuple, return_count);
			return return_count;
		}
	};

/*
template<typename T, typename... A, void (T::*f)(A...)>
int xLB_adapter(lua_State* L) {
	using arg_tuple_t = std::tuple<T*,A...>;
	using idxer_t = typename xLB_toidxer<T*,A...>::type;
	idxer_t indexer;
	arg_tuple_t tuple;
	xLB_getter(L, tuple, indexer);
	xLB_call<f>(tuple);
	return 0;
}
*/

/*---------------------------------------------------------------------------
xLB_return_void
-----------------------------------------------------------------------------*/
template<typename Tx> struct xLB_return_void {
		static const bool value = true;
	};

template<typename Tx, class R, class ...A> 
	struct xLB_return_void<R (Tx::*)(A...)> {
		static const bool value = std::is_void<R>::value;
	};


/*---------------------------------------------------------------------------

-----------------------------------------------------------------------------*/
template<typename T> struct xLB_xotrait{ static char meta[]; };

typedef std::vector<nbCPChar> xLB_namelist_t;
int xLB_search(lua_State* L, nbCPChar method_name, const xLB_namelist_t& nlst);
int xLB_rawsearch(lua_State* L, nbCPChar method_name, nbCPChar meta_name);


/*---------------------------------------------------------------------------
xLB_proxy
-----------------------------------------------------------------------------*/
//template<class Tx, Tx, bool, int...RPI> struct xLB_proxy;
template<class Tx, Tx, bool, class> struct xLB_proxy;

template<class Tx, class R, class ...A, R (Tx::*f)(A...), int...RPI>
	struct xLB_proxy<R (Tx::*)(A...), f, false, xLB_idxer<RPI...>> {
		static inline void b(xLB_xobase<Tx>* xobinder, const char fn[]) { 
			xobinder->rg_meta.push_back({fn, 
					&xLB_adapter<R, Tx, R (Tx::*)(A...), f, xLB_idxer<RPI...>, A...>
					}); 
		}
	};

template<class Tx, class ...A, void (Tx::*f)(A...), int...RPI>
	struct xLB_proxy<void (Tx::*)(A...), f, true, xLB_idxer<RPI...>> {
		static inline void b(xLB_xobase<Tx>* xobinder, const char fn[]) {
			xobinder->rg_meta.push_back({fn, 
					xLB_adapter_void<Tx, void (Tx::*)(A...), f, xLB_idxer<RPI...>, A...>
					}); 
		}
	};

/*---------------------------------------------------------------------------
xLB_xobase
-----------------------------------------------------------------------------*/
template<typename X>
struct xLB_xobase {
	typedef X T;
	typedef xLB_xobase self_t;
	typedef xLB_xobase* this_t;
	typedef xLB_xotrait<T> trait_t;
	typedef std::vector<luaL_reg> regs_t;
	static const char meta_name[];
	static const char type_name[];
	static xLB_namelist_t super_name_list;
	regs_t rg_meta;
	regs_t rg_type;
	virtual ~xLB_xobase() {}

	static int index_implement(lua_State* L) { //__index(t,k)
		auto method_name = luaL_optlstring(L, 2, "", nullptr);
		int nFound = xLB_rawsearch(L, method_name, meta_name);
		if (!nFound) {
			nFound = xLB_search(L, method_name, super_name_list);
		}
		return nFound;
	}

	void newxometatable(lua_State* L) {
		luaL_newmetatable(L, trait_t::meta_name);
		lua_pushstring(L, "__index");
		lua_pushcfunction(L, index_implement);
		lua_rawset(L, -3);
		// set metatable.metatable to itself
		lua_pushvalue(L, -1);
		lua_setmetatable(L, -2);
		luaL_setfuncs(L, &rg_meta[0], 0);
		lua_pop(L, 1); // pop metatable
	}

	template<class SUPER_XO> void super() { 
		super_name_list.push_back(xLB_xotrait<SUPER_XO>::meta_name); 
	}
	template<lua_CFunction f> void c(const char fn[]="new") { 
		rg_type.push_back({fn,f});
	}

	//inline void pushf(regs_t& rs, const char* n, lua_CFunction f) {
		luaL_reg r{n,f}; rs.push_back(r);
		//rs.push_back({n, f});
	//}
	//template<lua_CFunction f> void c() { pushf(rg_type, "new", f); }
		//pushf(rg_type, fn, f); 
			//pushf(rg_meta, fn, xLB_xomethod<T, f>); 
			//pushf(rg_meta, fn, f); 
		//pushf(rg_meta, nullptr, nullptr);
			//xLB_newmetatable(L, trait_t::meta_name, &rg_meta[0]);
			//pushf(rg_type, nullptr, nullptr);
/*---------------------------------------------------------------------------
bind function
-----------------------------------------------------------------------------*/
	template<typename xLB_method<T>::type f> void b(const char fn[]) { 
			rg_meta.push_back({fn, xLB_xomethod<T, f>});
		}
	template<lua_CFunction f> void b(const char fn[]) { 
			rg_meta.push_back({fn,f});
		}
	//template<class FT, FT f, int...RPI> void b(const char fn[]) {
	//		xLB_proxy<FT, f, xLB_return_void<FT>::value, RPI...>::b(this, fn);
	//	}
	template<class FT, FT f, class RPIs = xLB_idxer<>> void b(const char fn[]) {
			xLB_proxy<FT, f, xLB_return_void<FT>::value, RPIs>::b(this, fn);
		}
	void d() { b<xLB_gcxo<T>>("__gc"); }
	void reg(lua_State* L, const char* ns = nullptr) {
		if (0 < rg_meta.size()) {
			rg_meta.push_back({nullptr,nullptr});
			newxometatable(L);
		}
		if (0 < rg_type.size()) {
			rg_type.push_back({nullptr,nullptr});
			luaL_newlib(L, &rg_type[0]);
			if (ns && strlen(ns)) {
				lua_getglobal(L, ns);
				if (LUA_TTABLE != lua_type(L, -1)) {
					lua_pop(L, 1);
					lua_newtable(L);
					lua_setglobal(L, ns);
					lua_getglobal(L, ns);
				}
				lua_pushstring(L, trait_t::type_name);
				lua_pushvalue(L, -3);
				lua_rawset(L, -3);
				lua_pop(L, 2);
			}
		}
	}
	
	//static T* getobj(lua_State* L, int index) {
		//return xLB_getxo<T>(L, index);	
	//}
}; // end of xLB_xobase

	//inline void pushf(regs_t& rs, const char* n, lua_CFunction f) {
		//luaL_reg r{n,f}; rs.push_back(r);
	//}
		//pushf(rg_table, "new", f); 
			//pushf(rg_table, fn, f); 
			//pushf(rg_table, nullptr, nullptr);
			//lua_newtable(L);
			//luaL_register(L, nullptr, &rg_table[0]);
			//pushf(rg_table, nullptr, nullptr);
			//lua_newtable(L);
			//luaL_register(L, nullptr, &rg_table[0]);
/*---------------------------------------------------------------------------
xLB_table
-----------------------------------------------------------------------------*/
template<typename X>
struct xLB_table {
	typedef X T;
	typedef xLB_table self_t;
	typedef xLB_table* this_t;
	typedef std::vector<luaL_reg> regs_t;
	virtual ~xLB_table() {}
	regs_t rg_table;
	template<lua_CFunction f> void c(const char fn[]) { 
		rg_table.push_back({fn,f});
	}
	template<lua_CFunction f>
		void b(const char fn[]) { 
			rg_table.push_back({fn,f});
		}
	void reg(lua_State* L, const char* tn, const char* ns = 0) {
		if (0 < rg_table.size()) {
			rg_table.push_back({nullptr,nullptr});
			luaL_newlib(L, &rg_table[0]);
			if (ns && strlen(ns)) {
				lua_getglobal(L, ns);
				int t = lua_type(L, -1);
				if (LUA_TNIL == t || LUA_TTABLE != t ) {
					lua_pop(L, 1);
					lua_newtable(L);
					lua_setglobal(L, ns);
					lua_getglobal(L, ns);
				}
				lua_pushstring(L, tn);
				lua_pushvalue(L, -3);
				lua_rawset(L, -3);
				lua_pop(L, 2);
			}
		}
	}
	void reg(lua_State* L, const char* tn, int index = 0) {
		if (0 < rg_table.size()) {
			rg_table.push_back({nullptr,nullptr});
			lua_pushstring(L, tn);
			luaL_newlib(L, &rg_table[0]);
			if (index < 0) { index-=2; }
			if (index) { lua_rawset(L, index); }
		}
	}
}; // end of xLB_table

#endif // end of __XLB_H__

xlb.cpp

#include <ns/xlb.h>

/*---------------------------------------------------------------------------
xLB_pusher
-----------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
lux_
-----------------------------------------------------------------------------*/
void xLB_newmetatable(lua_State* L, const char* LibName, luaL_Reg* Lreg) {
	luaL_newmetatable(L, LibName);
	lua_pushstring(L, "__index");
	lua_pushvalue(L, -2);
	lua_rawset(L, -3);
	// set metatable to "key" weak table
	//lua_pushstring(L, "__mode");
	//lua_pushstring(L, "k");
	//lua_rawset(L, -3);
	// set metatable.metatable to itself
	lua_pushvalue(L, -1);
	lua_setmetatable(L, -2);
	//luaL_register(L, nullptr, Lreg);
	luaL_setfuncs(L, Lreg, 0/*no upvalue for funcs to share*/);
	lua_pop(L, 1); // pop metatable
}

int xLB_search(lua_State* L, nbCPChar method_name, const xLB_namelist_t& nlst) {
	int nFound = 0;
	for (auto meta_name : nlst) {
		lua_getfield(L, LUA_REGISTRYINDEX, meta_name);
		if (!lua_istable(L, -1)) { 
			nb_warn(true, "%s not registered", meta_name); 
			return 0;
		} else {
			lua_pushstring(L, method_name);
			lua_gettable(L, -2);
			lua_replace(L, -2);
			nFound = (lua_isnil(L, -1) ? 0 : 1);
			if (nFound) break;
		}
	}
	return nFound;
}

int xLB_rawsearch(lua_State* L, nbCPChar method_name, nbCPChar meta_name) {
	//nb_warn(true, "search: %s in %s", method_name, meta_name);
	lua_getfield(L, LUA_REGISTRYINDEX, meta_name);
	if (!lua_istable(L, -1)) { 
		nb_warn(true, "%s not registered", meta_name); 
		return 0;
	} else {
		lua_pushstring(L, method_name);
		lua_rawget(L, -2);
		lua_replace(L, -2);
		return (lua_isnil(L, -1) ? 0 : 1);
	}
}

void xLB_userdata(lua_State* L, const char* LibName, lua_Number N) {
	// s: 1(ud)
	int inew = luaL_newmetatable(L, LibName); // s: 1(ud), 2(metatable)
	//if (inew) throw std::logic_error("metatable muse be registered");
	nb_warn(inew, "xLB-Error: %d %s", inew, LibName);
	//lua_pushvalue(L, -2); // duplicate userdata as key
	//lua_pushnumber(L, N); // value:0 arbitrary
	//lua_settable(L, -3); // metatable[userdata] = value(0)
	lua_setmetatable(L, -2); // userdata.metatable = metatable
}


void xLB_newnstable(lua_State* L, const char* name, const char* ns) {
	lua_getglobal(L, ns);
	if (LUA_TTABLE == lua_type(L, -1)) {
		lua_pushstring(L, name);
		lua_newtable(L); 
		lua_rawset(L, -3);
	}
	lua_pop(L, 1);
}

void xLB_newnstable(lua_State* L, const char* tn, int index) {
	lua_pushstring(L, tn);
	lua_newtable(L);
	if (index < 0) { index-=2; }
	lua_rawset(L, index);
}

/*
void xLB_getnstable(lua_State* L, const char* name, const char* ns) {
	lua_getglobal(L, ns);
	lua_pushlstring(L, name, strlen(name));
	lua_rawget(L, -2);
	lua_insert(L, -2);
	lua_pop(L, 1);
}
*/

调用xlb

xlbinder.h

#ifndef _XLBINDER_H
#define _XLBINDER_H

#include <ns/xlb.h>
#include <type_traits>


struct clsB {
	void b() { printf("clsB::b() called\n"); }
};

xLB_xodeclare(clsB) {
	xLB_xotrait() {
		b<decltype(&clsB::b), &clsB::b>("b");
	}
};

struct clsA : public clsB {
	int Add(int a, int& b);
	int Del(int* a);
	int Modify(int& a);
	void NoReturn(int a);
}; // end of clsA

void foo(int a);
int g(int a);

xLB_xodeclare(clsA) {
	xLB_xotrait() {
		super<clsB>();
		//1.
		//lua_CFunction p = xLB_adapter<int, clsA, decltype(&clsA::Add), &clsA::Add, int, int>;
		//b<xLB_adapter<int, clsA, decltype(&clsA::Add), &clsA::Add, int, int>>("Add");
		//2.
		//proxy<decltype(&clsA::Add), &clsA::Add, false>::b(this, "Add");
		
		//b<decltype(&clsA::Add), &clsA::Add>("Add");
		b<decltype(&clsA::Add), &clsA::Add, xLB_rpi<1,0>>("Add");
		//b<decltype(&clsA::Add), &clsA::Add,xLB_idxer<1,0>>("Add");
		//b<decltype(&clsA::Del), &clsA::Del>("Del");
		b<decltype(&clsA::NoReturn), &clsA::NoReturn, xLB_idxer<0>>("NoReturn");

		//proxy<int (clsA::*)(int,int), &clsA::Add, false>::b(this, "Add");
		//proxy<int (clsA::*)(int), &clsA::Add, false>::b(this, "Add2");

		//proxy<decltype(&clsA::Modify), &clsA::Modify, false>::b(this, "Modify");
		//proxy<decltype(&clsA::NoReturn), &clsA::NoReturn, true>::b(this, "NoReturn");
	}
};

#endif

xlbinder.cpp

#include "xlbinder.h"

xLB_xodefine(clsA);
xLB_xodefine(clsB);


int clsA::Add(int a, int& b) { 
	printf("clsA::Add(%d,%d):%d called\n", a,b,a+b);
	b+=123;
	return a+b; 
}
int clsA::Del(int* a) { printf("obj:Del called: %d\n", *a); return *a = 2; };
int clsA::Modify(int& a) { return a*=2; }
void clsA::NoReturn(int a) { printf("obj:NoReturn called: %d\n", a*3); }

void foo(int a) {
	printf("foo called: %d\n", a);
}

int g(int a) {
	printf("g called: %d\n", a);
	return a+2;
}

int main() {
	std::cout << "xLB_adapter test ... \n";
	auto L = luaL_newstate();
	luaL_openlibs(L);
	xLB_bindxo<clsB>(L);
	xLB_bindxo<clsA>(L);
	clsA obj;
	xLB_xoglobal<clsA>(L, &obj, "obj");
	luaL_dostring(L, "print('Lua{');");
	luaL_dostring(L, "print('getmetatable(obj)={');");
	luaL_dostring(L, "for k,v in pairs(getmetatable(obj)) do print('  ' .. k .. '=' .. tostring(v)); end");
	luaL_dostring(L, "print('}');");
	luaL_dostring(L, "print(obj:Add(99,2));");
	//luaL_dostring(L, "print('obj:Add(99,2)=' .. tostring(obj:Add(99,2)));");

	//luaL_dostring(L, "d = obj:Del(8);");
	//luaL_dostring(L, "print('obj:Del(8)=' .. tostring(d));"); 
	
	//luaL_dostring(L, "print('obj:Modify(8)=' .. tostring(obj:Modify(8)));");
	
	luaL_dostring(L, "x = obj:NoReturn(8); ");
	luaL_dostring(L, "print('obj:NoReturn(8)=' .. tostring(x));");
	
	//---
	//auto x = &xLB_CFunc<decltype(&foo), &foo>::voidfunc;
	//&xLB_CFunc<decltype(&foo), &foo>::voidfunc
	lua_register(L, "foo", &(xLB_CFunc<decltype(&foo), &foo>::adapter));
	luaL_dostring(L, "x = foo(1901); print(tostring(x));");

	lua_register(L, "g", &(xLB_CFunc<decltype(&g), &g, 0>::adapter));
	luaL_dostring(L, "print(g(1999));");

	//---
	luaL_dostring(L, "obj:b()");

	lua_close(L);
	printf("}\n");
	return 0;
}

//inline void xLB_pusher(lua_State* L, int r, int& return_count) { 
	//lua_pushinteger(L, r); ++return_count; 
//}











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值