20140218-lua binder另一只轮子的雏形(2014-01-02 20:08)

来源:互联网 发布:淘宝鹊桥入口在哪里 编辑:程序博客网 时间:2024/05/21 09:09

书接上一回,继续补充xlb的功能。这次修改代码的代码比添加功能的代码还多,完成后大致包括

  • 添加了支持overload和override函数绑定,支持绑定属性;
  • 添加了构造函数绑定,释构函数绑定前面已经实现了,这次是把名字修改了;
  • 修改函数参数提取过程,支持非一对一提取,即是一个函数形参可以从lua_State中提取N个参数(0<=N<=lua_gettop(L)),不过这一功能的具体用途还不是很清晰;
  • 添加绑定函数执行过程错误提示;
  • xlb变成单个头文件的形式;

添加绑定常量得等下一回继续。从C++调用lua这部分还没开始,还有许多功能需要实现,向luabind等学习,继续丰富其功能。xlb没有使用upvalue,纯模板编译时确定,因为还有许多功能未实现,现在仍不知道这会不会带来麻烦。

测试代码:

for k,v in pairs(clsA) doprint(k,v);endobjC:override_();local f = obj.override_;f(objC);local f = objC.override_;f(objC);print(objC);print(objC.z);print(objC.x);objC.x = 1;print(objC.x);objC:b();local f = objC.b;print(another);f(obj);print(obj.x);for k,v in pairs(getmetatable(obj)) doprint(k,v);endprint(tostring(obj));obj:NoReturn(555);obj:NoReturn();obj:Add(1,2);obj:Add2(1,2,3);obj.Add2(obj,1,2,3);print(g(54321));foo();foo(1);x=clsA.new(777);x:Complex(x);x = nil;collectgarbage();


执行结果:

new     function: 0040A128clsC::override_clsA::override_clsC::override_xLB_object: 0x0022FEC412343331base class clsB::b() method calledxLB_object: 0x0022FEDBbase class clsB::b() method called111__newindex      function: 0040AFC4__tostring      function: 0040B150xLB_meta        xLB_clsAxLB_super       table: 005D9B20xLB_ancient     table: 005D9AF8__gc    function: 0040A860__index function: 0040AE64xLB_object: 0x0022FED0obj:NoReturn[a=555]obj:NoReturn[a=8888]clsA::Add(1,2):3 calledclsA::Add(int,int,int):1+2+3=6 calledclsA::Add(int,int,int):1+2+3=6 calledg(54321)54323foo called.foo called: 1obj:Complex[clsA*=0x005d2890, pa->x=777](0x005d2890)x=777,free(0x0022fec4)x=1,free(0x0022fed0)x=111,free


luabind.h

#ifndef _XLBINDER_H#define _XLBINDER_H#include <ns/xlb.h>#include <type_traits>struct clsAnother {};xLB_xodeclare(clsAnother) {}struct clsB {void b() { printf("base class clsB::b() method called\n"); }int z = 1234;};struct clsA : public clsB {clsA(int a=0) : x(a) {}~clsA() { printf("(0x%p)x=%d,free\n", this,x); }int Add(int a, int& b);void Add(int a, int b, int c) const;int Del(int* a);int Modify(int& a);void NoReturn(int a);void Complex(clsA* pa);int x = 999;void override_() { printf("clsA::override_\n"); }}; // end of clsAstruct clsC : public clsA {void override_() { printf("clsC::override_\n"); }int y = 1000;};xLB_xodeclare(clsB) {def("b", xLB_cfunction<decltype(&clsB::b), &clsB::b>);def_readwrite<decltype(&clsB::z), &clsB::z>("z");}struct My_vter : public xLB_vter {};template<> struct My_vter::xLB_tir<clsA*> { using type = clsA*; };struct My_lver : public xLB_lver {//template<class TUP_ELE, class V> struct xLB_tir {};};template<class TUP_ELE>struct My_lver::xLB_tir<TUP_ELE, clsA*> {template<class TUP>static inline void go(lua_State* L, TUP_ELE& tuple_val, TUP& tuple, xLB_ami& ami) {auto obj = xLB_getdynamicud<clsA>(L, ami.next_index);if (obj) {tuple_val= obj;++ami.next_index;} else {ami.type_match = XLB_AMI_BAD;ami.extmsg = "clsA* expected";}}};//struct My_dfer : public xLB_dfer {struct My_dfer {template<class TUP> static inline int go(TUP& tuple) {return xLB_defaultarguments(tuple, 8888);}};xLB_xodeclare(clsA) {super<clsB>();constructor("new", xLB_cfunction<decltype(&xLB_newer<int>),&xLB_newer<int>,xLB_dfer,xLB_idxer<>,xLB_pper,xLB_rner_newobj>);def("NoReturn", xLB_cfunction<decltype(&clsA::NoReturn), &clsA::NoReturn, My_dfer, xLB_idxer<0>>);def("Complex", xLB_cfunction<decltype(&clsA::Complex), &clsA::Complex>);def("Add2", xLB_cfunction<void (clsA::*)(int, int, int) const, &clsA::Add>);def("Add", xLB_cfunction<xLB_cfunction<int (clsA::*)(int,int&), &clsA::Add>, xLB_cfunction<void (clsA::*)(int,int,int) const, &clsA::Add>>);def_readwrite<decltype(&clsA::x), &clsA::x>("x");def("override_", xLB_cfunction<decltype(&clsA::override_), &clsA::override_>);destructor();};xLB_xodeclare(clsC) {super<clsA>();def("override_", xLB_cfunction<decltype(&clsC::override_), &clsC::override_>);}struct mytype {int a;};void foo(int a);int g(int a);int h(clsA* a);void v(int n, ...);#endif

xlbind.cpp

#include "xlbinder.h"//----------------------------------------------------------------------void foo(int a) { printf("foo called: %d\n", a); }void foo() { printf("foo called. \n" ); }int g(int a) { printf("g(%d)\n", a); return a+2; }int h(clsA* a) { printf("h called: %d\n", a->x); return 0; }int h2(clsA* a) { printf("h2 called: %d\n", a->x); return 0; }void v(int n, ...) {printf("%d", n);}//----------------------------------------------------------------------int clsA::Add(int a, int& b) { printf("clsA::Add(%d,%d):%d called\n", a,b,a+b);return a+b; }void clsA::Add(int a, int b, int c) const { printf("clsA::Add(int,int,int):%d+%d+%d=%d called\n", a,b,c,a+b+c);}int clsA::Del(int* a) { printf("obj:Del[int* a=%d]\n", *a); return *a-=2; };int clsA::Modify(int& a) { printf("obj:Modify[int& a=%d]\n", a); return a*=2; }void clsA::NoReturn(int a) { printf("obj:NoReturn[a=%d]\n", a); }void clsA::Complex(clsA* pa) { printf("obj:Complex[clsA*=0x%p, pa->x=%d]\n", (void*)pa, pa->x); }//----------------------------------------------------------------------xLB_xodefine(clsAnother);xLB_xodefine(clsA);xLB_xodefine(clsB);xLB_xodefine(clsC);//----------------------------------------------------------------------------#define test(L, s) \printf("run[\n%s\n]\n", s); \luaL_loadstring(L, s); \if (lua_pcall(L, 0, LUA_MULTRET, 0)) { \printf("%s\n", lua_tostring(L, -1)); \lua_pop(L, 1); \} \//----------------------------------------------------------------------------int main(int argc, char** args) {auto L = luaL_newstate();luaL_openlibs(L);xLB_bindxo<clsAnother>(L);clsAnother another;xLB_xoglobal<clsAnother>(L, &another, "another");xLB_bindxo<clsB>(L);xLB_bindxo<clsA>(L);xLB_bindxo<clsC>(L);clsA obj;obj.x = 111;xLB_xoglobal<clsA>(L, &obj, "obj");clsC objC;objC.x = 333;objC.y = 100;xLB_xoglobal<clsC>(L, &objC, "objC");//lua_register(L, "v", (xLB_cfunction<decltype(&v), &v>));lua_register(L, "g", (xLB_cfunction<decltype(&g), &g>));lua_register(L, "foo", (xLB_cfunction<  xLB_cfunction<void (*)(int), &foo>, xLB_cfunction<void (*)(), &foo>>));if (argc>=2) {luaL_loadfile(L, args[1]); \if (lua_pcall(L, 0, LUA_MULTRET, 0)) { \printf("%s\n", lua_tostring(L, -1)); \lua_pop(L, 1); \}}lua_close(L);return 0;}

xlb.h

#ifndef _XLB_H#define _XLB_H#include <iostream>#include <vector>#include <assert.h>#include <cstring>#include <tuple>#include <memory>#include <type_traits>#include <array>#include <unordered_map>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;struct xLB_util;#define luaL_reg luaL_Reg#define XLB_TRAP_FLAG 0xFF#define XLB_EXISTS_FLAG 0x1// 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/*---------------------------------------------------------------------------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;}template<typename T>inline T* xLB_getxo(lua_State* L, int index) {return xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, index);}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>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_typelist-----------------------------------------------------------------------------*/template<class...types> struct xLB_typelist {static int const size = sizeof...(types);};/*---------------------------------------------------------------------------xLB_creatidxer-----------------------------------------------------------------------------*/template<int...> struct xLB_idxer{}; template<int...RPI> using xLB_rpi = xLB_idxer<RPI...>; // xLB_idxer aliasusing xLB_rier = xLB_idxer<>;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_arginfo-----------------------------------------------------------------------------*/struct xLB_arginfo {int from = 0;int to = 0;int type = 0;};/*---------------------------------------------------------------------------xLB_typelist-----------------------------------------------------------------------------*/template<class VTER, class FT> struct xLB_typeforge {};template<class VTER, class R, class Tx, class...A> struct xLB_typeforge<VTER, R(Tx::*)(A...)> {using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;using idxer_t = typename xLB_toidxer<A...>::type;using vter_arg_t = xLB_typelist<typename VTER::template xLB_tir<A>::type...>;using arg_t = xLB_typelist<A...>;using return_t = R;using obj_t = Tx;using arginfo_t = array<xLB_arginfo, sizeof...(A)>;};template<class VTER, class R, class Tx, class...A> struct xLB_typeforge<VTER, R(Tx::*)(A...) const> {using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;using idxer_t = typename xLB_toidxer<A...>::type;using vter_arg_t = xLB_typelist<typename VTER::template xLB_tir<A>::type...>;using arg_t = xLB_typelist<A...>;using return_t = R;using obj_t = Tx;using arginfo_t = array<xLB_arginfo, sizeof...(A)>;};template<class VTER, class R, class...A> struct xLB_typeforge<VTER, R(*)(A...)> {using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;using idxer_t = typename xLB_toidxer<A...>::type;using vter_arg_t = xLB_typelist<typename VTER::template xLB_tir<A>::type...>;using arg_t = xLB_typelist<A...>;using return_t = R;using obj_t = void;using arginfo_t = array<xLB_arginfo, sizeof...(A)>;};/*---------------------------------------------------------------------------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_util-----------------------------------------------------------------------------*/struct xLB_util {static void xLB_userdata(lua_State* L, const char* LibName, lua_Number N) {luaL_newmetatable(L, LibName); // s: 1(ud), 2(metatable)lua_setmetatable(L, -2); // ud.metatable = metatable}static void newxometatable(lua_State* L, const char* meta, const std::vector<luaL_reg>& rg_meta,const std::vector<const char*>& super_names) {luaL_newmetatable(L, meta);if (1 < rg_meta.size()) {luaL_setfuncs(L, &rg_meta.front(), 0);}// set metatable.metatable to itselflua_pushvalue(L, -1);lua_setmetatable(L, -2);lua_pushstring(L, "xLB_meta");lua_pushstring(L, meta);lua_rawset(L, -3);lua_pushstring(L, "xLB_ancient");lua_newtable(L);lua_rawset(L, -3);lua_pushstring(L, "xLB_super");lua_newtable(L);for (auto meta_name : super_names) {lua_pushstring(L, meta_name);lua_pushnumber(L, XLB_EXISTS_FLAG);lua_rawset(L, -3);}lua_rawset(L, -3);lua_pop(L, 1); // pop metatable}static void registertypetable(lua_State* L, const char* type_name, std::vector<luaL_reg>& rg_type, int parent_table_index) {if (1 < rg_type.size()) {if (parent_table_index != 0) {lua_pushstring(L, type_name);luaL_newlib(L, &rg_type.front());if (parent_table_index < 0) { parent_table_index -= 2; }lua_rawset(L, parent_table_index);} else {luaL_newlib(L, &rg_type.front());lua_setglobal(L, type_name);}}}static int search_getter(lua_State* L, const char* meta_name,std::vector<const char*>& super_names) {int nfound = 0;for (auto meta_name : super_names) {lua_getfield(L, LUA_REGISTRYINDEX, meta_name);assert(lua_istable(L, -1));lua_pushstring(L, "__index");lua_rawget(L, -2);lua_pushvalue(L, 1);lua_pushvalue(L, 2);// Note: manual call __index, instead using lua_gettable// since the value one the 1 index must be userdatalua_pcall(L, 2, 1, 0); lua_remove(L, -2); // remove metatableif (lua_isnil(L, -1)) {lua_pop(L, 1);} else {nfound = 1;break;}}return nfound;}static int search_setter(lua_State* L, const char* meta_name,std::vector<const char*>& super_names) {int nfound = 0;for (auto meta_name : super_names) {lua_getfield(L, LUA_REGISTRYINDEX, meta_name);assert(lua_istable(L, -1));lua_pushstring(L, "__newindex");lua_rawget(L, -2);lua_remove(L, -2); // remove metatablelua_pushvalue(L, 1);lua_pushvalue(L, 2);lua_pushvalue(L, 3);// Notes: push additional argument(XLB_TRAP_FLAG) for __newindex callinglua_pushnumber(L, XLB_TRAP_FLAG);// Note: manual call __newindex, instead using lua_settable// since the value one the 1 index must be userdatalua_pcall(L, 4, 1, 0); if (lua_isnil(L, -1)) {lua_pop(L, 1);} else {nfound = 1;break;}}return nfound;}static bool isderiveduserdata(lua_State* L, int index, const char* meta_name) {//-1:xLB_super={...}std::vector<string> table_names;lua_pushnil(L);while (lua_next(L, index) != 0) {table_names.push_back(string(lua_tostring(L,-2)));lua_pop(L, 1);}while (!table_names.empty()) {string table_name = table_names.back();table_names.pop_back();if (table_name == meta_name) {return true;} else {lua_getfield(L, LUA_REGISTRYINDEX, table_name.c_str());lua_pushstring(L, "xLB_super");lua_rawget(L, -2);if (lua_istable(L, -1)) { auto table_index = lua_gettop(L);lua_pushnil(L);while (lua_next(L, table_index) != 0) {table_names.push_back(string(lua_tostring(L, -2)));lua_pop(L, 1);}}lua_pop(L, 2);}}return false;}static bool dynamic(lua_State* L, int index, const char* meta_name) {bool isderived = false;if (lua_isuserdata(L, index)) {lua_getmetatable(L, index);lua_pushstring(L, "xLB_meta");lua_rawget(L, -2);isderived = (strcmp(meta_name, lua_tostring(L, -1)) == 0);lua_pop(L, 1); // pop xLB_meta's valueif (!isderived) {lua_pushstring(L, "xLB_ancient");lua_rawget(L, -2);if (!lua_istable(L, -1)) {lua_pop(L, 1);lua_pushstring(L, "xLB_ancient");lua_newtable(L);lua_rawset(L, -3);lua_pushstring(L, "xLB_ancient");lua_rawget(L, -2);}lua_pushstring(L, meta_name);lua_rawget(L, -2);isderived = !lua_isnil(L, -1);lua_pop(L, 2);if (!isderived) {lua_pushstring(L, "xLB_super");lua_rawget(L, -2);if (lua_istable(L, -1)) {isderived = xLB_util::isderiveduserdata(L, lua_gettop(L), meta_name);}lua_pop(L, 1); // xLB_super's valueif (isderived) {lua_pushstring(L, "xLB_ancient");lua_rawget(L, -2);lua_pushstring(L, meta_name);lua_pushnumber(L, 1);lua_rawset(L, -3);lua_pop(L, 1);}}}lua_pop(L, 1); // pop metatable}return isderived;}};/* 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_util::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_util::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_util::xLB_userdata(L, xLB_xotrait<T>::meta_name, 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;}/*---------------------------------------------------------------------------xLB_getdynamicud-----------------------------------------------------------------------------*/template<class T>inline T* xLB_getdynamicud(lua_State* L, int index) {if (xLB_util::dynamic(L, index, xLB_xotrait<T>::meta_name)) {auto wp = reinterpret_cast<xLB_ludwrap<T>*>(lua_touserdata(L, index)); // index>0return wp->ptr();} else {return nullptr;}}/*---------------------------------------------------------------------------xLB_dferfunction default parameters provider-----------------------------------------------------------------------------*/struct xLB_dfer {//template<class TUP> struct xLB_tir {//static inline int go(TUP& tuple) { return 0; }//};template<class TUP>static inline int go(TUP& tuple) { return 0; }};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 int xLB_defaultarguments(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...);return sizeof...(DA);}/*---------------------------------------------------------------------------xLB type match-----------------------------------------------------------------------------*/#define XLB_AMI_BAD           0x10000000#define XLB_AMI_DENY          0x10000001#define XLB_AMI_NONE          0x10000002#define XLB_AMI_FEW           0x10000003#define XLB_AMI_TOMUCH        0x10000003#define XLB_AMI_SAME          0x0#define XLB_AMI_DEFAULT       0x0#define XLB_AMI_TRANSLATE     0x1#define xLB_badtype(tmi) (XLB_AMI_BAD <= (tmi.type_match))struct xLB_ami {int type_match = XLB_AMI_SAME;int narg = 0;int next_index = 0;const char* extmsg = "";int top = 0;int default_count = 0;int arg_count = 0;int return_count = 0;void* obj = nullptr;};/*---------------------------------------------------------------------------xLB_lver-----------------------------------------------------------------------------*/struct xLB_lver {template<class TUP_ELE, class V> struct xLB_tir {template<class TUP>static inline void go(lua_State* L, TUP_ELE& tuple_val, TUP& tuple, xLB_ami& ami) {ami.type_match = XLB_AMI_BAD;ami.extmsg = "xLB_lver not implemented";}};};template<class Tx>struct xLB_lver::xLB_tir<Tx*, Tx> {template<class TUP>static inline void go(lua_State* L, Tx*& tuple_val, TUP& tuple, xLB_ami& ami) {auto obj = xLB_getdynamicud<Tx>(L, ami.next_index); // narg==1if (obj) {tuple_val = obj;++ami.next_index;} else {ami.type_match = XLB_AMI_BAD;ami.extmsg = "self invalid";}}};template<class TUP_ELE>struct xLB_lver::xLB_tir<TUP_ELE, int> {template<class TUP>static inline void go(lua_State* L, TUP_ELE& tuple_val, TUP& tuple, xLB_ami& ami) {auto index = ami.next_index;if (lua_isnumber(L, index)) {tuple_val = lua_tointeger(L, index);++ami.next_index;} else {ami.type_match = XLB_AMI_BAD;ami.extmsg = "integer expected";}}};template<class TUP_ELE>struct xLB_lver::xLB_tir<TUP_ELE, double> {template<class TUP>static inline void go(lua_State* L, TUP_ELE& tuple_val, TUP& tuple, xLB_ami& ami) {auto index = ami.next_index;if (lua_isnumber(L, index)) {tuple_val = lua_tonumber(L, index);++ami.next_index;} else {ami.type_match = XLB_AMI_BAD;ami.extmsg = "double expected";}}};/*---------------------------------------------------------------------------xLB_fver-----------------------------------------------------------------------------*/template<class LVER, class TUP, class IDXER, class TYPELIST>struct xLB_fver {};template<class LVER, class TUP>struct xLB_fver<LVER, TUP, xLB_idxer<>, xLB_typelist<>> {template<class ARGINFO>static inline void go(lua_State* L, TUP& tuple, ARGINFO& arginfo, xLB_ami& ami) { if (ami.top >= ami.next_index) {ami.type_match = XLB_AMI_TOMUCH;ami.extmsg = "too much argument";}}};template<class LVER, class TUP, int narg, int...idxs, class Head, class...Tail>struct xLB_fver<LVER, TUP, xLB_idxer<narg, idxs...>, xLB_typelist<Head, Tail...>> {template<class ARGINFO>static inline void go(lua_State* L, TUP& tuple, ARGINFO& arginfo, xLB_ami& ami) {if (ami.top >= ami.next_index) {ami.narg = narg; // Note:auto& ai = arginfo[narg];ai.from = ami.next_index;ai.type = lua_type(L, ami.next_index);LVER::template xLB_tir<typename std::tuple_element<narg, TUP>::type, Head>::go(L, std::get<narg>(tuple), tuple, ami);ai.to = ami.next_index-1;} else { ami.type_match = XLB_AMI_FEW; }if (xLB_badtype(ami)) {if (ami.type_match == XLB_AMI_FEW) {auto stack_remain = (ami.top - (ami.next_index - 1));auto arguments_remain = (ami.arg_count - ami.narg);if (stack_remain - arguments_remain + ami.default_count >= 0) {ami.type_match = XLB_AMI_DEFAULT;} else {ami.extmsg = "too few argument";}}} else {xLB_fver<LVER, TUP, xLB_idxer<idxs...>, xLB_typelist<Tail...>>::go(L, tuple, arginfo, ami);}}};/*---------------------------------------------------------------------------xLB_pperpush data(parameters of function) into lua_State-----------------------------------------------------------------------------*/struct xLB_pper {template<typename T> struct xLB_tir {static inline void go(lua_State* L, int narg, T tuple_val, const xLB_arginfo& ai, int& return_count) {static_assert(std::is_pod<T>::value, "xLB_pper is not implemented.\n");printf("xLB_pper is not implemented.\n");//lua_pushnumber(L, tuple_val); ++return_count; }};};template<> struct xLB_pper::xLB_tir<int> { static inline void go(lua_State* L, int narg, int tuple_val, const xLB_arginfo& ai, int& return_count) { lua_pushinteger(L, tuple_val); ++return_count; }};template<> struct xLB_pper::xLB_tir<const char*> {static inline void go(lua_State* L, int narg, const char* tuple_val, const xLB_arginfo& ai, int& return_count) { lua_pushstring(L, tuple_val); ++return_count; }};template<> struct xLB_pper::xLB_tir<double> { static inline void go(lua_State* L, int narg, double tuple_val, const xLB_arginfo& ai, int& return_count) { lua_pushnumber(L, tuple_val); ++return_count; }};template<> struct xLB_pper::xLB_tir<long> { static inline void go(lua_State* L, int narg, long tuple_val, const xLB_arginfo& ai, int& return_count) { lua_pushnumber(L, tuple_val); ++return_count; }};template<> struct xLB_pper::xLB_tir<bool> { static inline void go(lua_State* L, int narg, bool tuple_val, const xLB_arginfo& ai, int& return_count) { lua_pushnumber(L, tuple_val); ++return_count; }};/*---------------------------------------------------------------------------xLB_pterpush 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> {template<class ARGINFO>static inline void go(lua_State* L, std::tuple<A...>& tuple, ARGINFO& arginfo, int& return_count) {xLB_each{ (PPER::template xLB_tir<typename std::tuple_element<RPI, std::tuple<A...>>::type>::go(L, RPI+1, std::get<RPI>(tuple), reinterpret_cast<const xLB_arginfo&>(arginfo[RPI]), return_count), 1)... };}};/*---------------------------------------------------------------------------xLB_rnerpush result of function into lua_State-----------------------------------------------------------------------------*/struct xLB_rner {template<class R, class PPER> struct xLB_tir {static inline void go(lua_State* L, int narg, const R& result_of_function, const xLB_arginfo& ai, int& return_count) {PPER::template xLB_tir<R>::go(L, narg, result_of_function, ai, return_count);}};};struct xLB_rner_newobj : public xLB_rner { // customize for return wrapper object;template<class T, class PPER> struct xLB_tir {static inline void go(lua_State* L, int narg, T pobj, const xLB_arginfo& pai, int& return_count) {using OBJ_TYPE = typename std::remove_pointer<T>::type;xLB_objasud<OBJ_TYPE, xLB_xotrait<OBJ_TYPE>::meta_name>(L, pobj);++return_count;}};};/*---------------------------------------------------------------------------xLB_vperchange 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_vterdecide 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<int&> { using type = int; };template<> struct xLB_vter::xLB_tir<double*> { using type = double; };/*---------------------------------------------------------------------------xLB_caler-----------------------------------------------------------------------------*/struct xLB_caler {template<class R, class Tx, class FT, class IDXER, class VPER, class TYPELIST, class RNER, class PPER> struct xLB_tir {};};template<class R, class Tx, class FT, class VPER, class...A, int...idxs, class RNER, class PPER> struct xLB_caler::xLB_tir<R, Tx, FT, xLB_idxer<idxs...>, VPER, xLB_typelist<A...>, RNER, PPER> {template<class...B> static inline void go(lua_State* L, xLB_ami& ami, FT f, std::tuple<B...>& tuple) {R r = (reinterpret_cast<Tx*&>(ami.obj)->*f)(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);const xLB_arginfo ai;RNER::template xLB_tir<R,PPER>::go(L, 0, r, ai, ami.return_count);}};template<class Tx, class FT, class VPER, class...A, int...idxs, class RNER, class PPER> struct xLB_caler::xLB_tir<void, Tx, FT, xLB_idxer<idxs...>, VPER, xLB_typelist<A...>, RNER, PPER> {template<class...B> static inline void go(lua_State* L, xLB_ami& ami, FT f, std::tuple<B...>& tuple) {(reinterpret_cast<Tx*&>(ami.obj)->*f)(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);}};template<class R, class FT, class VPER, class...A, int...idxs, class RNER, class PPER> struct xLB_caler::xLB_tir<R, void, FT, xLB_idxer<idxs...>, VPER, xLB_typelist<A...>, RNER, PPER> {template<class...B> static inline void go(lua_State* L, xLB_ami& ami, FT f, std::tuple<B...>& tuple) {R r = f(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);const xLB_arginfo ai;RNER::template xLB_tir<R,PPER>::go(L, 0, r, ai, ami.return_count);}};template<class FT, class VPER, class...A, int...idxs, class RNER, class PPER> struct xLB_caler::xLB_tir<void, void, FT, xLB_idxer<idxs...>, VPER, xLB_typelist<A...>, RNER, PPER> {template<class...B> static inline void go(lua_State* L, xLB_ami&, FT f, std::tuple<B...>& tuple) {f(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);}};/*---------------------------------------------------------------------------xLB_each_ovlfunc-----------------------------------------------------------------------------*/using xLB_ovlfunc = void (*)(lua_State* L, xLB_ami& ami);template <xLB_ovlfunc... Fs>struct xLB_each_ovlfunc_impl;template <xLB_ovlfunc F>struct xLB_each_ovlfunc_impl<F> {static void go(lua_State* L, xLB_ami& ami) {ami.type_match = XLB_AMI_SAME;F(L, ami);}};template <xLB_ovlfunc F, xLB_ovlfunc...Fs>struct xLB_each_ovlfunc_impl<F, Fs...> {static inline void go(lua_State* L, xLB_ami& ami) {ami.type_match = XLB_AMI_SAME;F(L, ami);if (xLB_badtype(ami)) {xLB_each_ovlfunc_impl<Fs...>::go(L, ami);}}};template <xLB_ovlfunc...Fs>inline void xLB_each_ovlfunc(lua_State* L, xLB_ami& ami) {xLB_each_ovlfunc_impl<Fs...>::go(L, ami);}/*---------------------------------------------------------------------------xLB_loadobj-----------------------------------------------------------------------------*/template<class Tx, class LVER>struct xLB_loadobj {template<class TUP, class ARGINFO>static inline void go(lua_State* L, TUP& tuple, xLB_ami& ami, ARGINFO& arginfo) {if (nullptr == ami.obj) {LVER::template xLB_tir<Tx*, Tx>::go(L, reinterpret_cast<Tx*&>(ami.obj), tuple, ami);}}};template<class LVER>struct xLB_loadobj<void, LVER> {template<class TUP, class ARGINFO>static inline void go(lua_State*, TUP& tuple, xLB_ami&, ARGINFO& arginfo) {}};/*---------------------------------------------------------------------------xLB_cfunctionoverload function-----------------------------------------------------------------------------*/template<class FT, FT f, class DFER=xLB_dfer, class RIER=xLB_rier, class PPER=xLB_pper, class RNER=xLB_rner, class PTER=xLB_pter, class VTER=xLB_vter, class LVER=xLB_lver, class VPER=xLB_vper>void xLB_cfunction(lua_State* L, xLB_ami& ami) {using forge_t = xLB_typeforge<VTER, FT>;using tuple_t = typename forge_t::tuple_t;using idxer_t = typename forge_t::idxer_t;using vter_arg_t = typename forge_t::vter_arg_t;using arg_t = typename forge_t::arg_t;using return_t = typename forge_t::return_t;using obj_t = typename forge_t::obj_t;using arginfo_t = typename forge_t::arginfo_t;arginfo_t arginfo;tuple_t tuple;ami.next_index = 1;ami.narg = 0;xLB_loadobj<obj_t, LVER>::go(L, tuple, ami, arginfo);if (!xLB_badtype(ami)) {ami.default_count = DFER::go(tuple);ami.arg_count = arg_t::size;xLB_fver<LVER, tuple_t, idxer_t, vter_arg_t>::go(L, tuple, arginfo, ami);}ami.return_count = ami.type_match;if (!xLB_badtype(ami)) {xLB_caler::template xLB_tir<return_t, obj_t, FT, idxer_t, VPER, arg_t, RNER, PPER>::go(L, ami, f, tuple);PTER::template xLB_tir<RIER, tuple_t, PPER>::go(L, tuple, arginfo, ami.return_count);}}/*---------------------------------------------------------------------------xLB_cfunctionoverload function-----------------------------------------------------------------------------*/template<xLB_ovlfunc F, xLB_ovlfunc...Fs>int xLB_cfunction(lua_State* L) {xLB_ami ami; ami.top = lua_gettop(L);ami.obj = nullptr;xLB_each_ovlfunc<F, Fs...>(L, ami);if (xLB_badtype(ami)) {return luaL_argerror(L, ami.next_index, ami.extmsg);}return ami.return_count;}/*---------------------------------------------------------------------------xLB_cfunctionnormal function-----------------------------------------------------------------------------*/template<class FT, FT f, class DFER=xLB_dfer,class RIER=xLB_rier, class PPER=xLB_pper,class RNER=xLB_rner,class PTER=xLB_pter,class VTER=xLB_vter, class LVER=xLB_lver, class VPER=xLB_vper> int xLB_cfunction(lua_State* L) {using forge_t = xLB_typeforge<VTER, FT>;using tuple_t = typename forge_t::tuple_t;using idxer_t = typename forge_t::idxer_t;using vter_arg_t = typename forge_t::vter_arg_t;using arg_t = typename forge_t::arg_t;using return_t = typename forge_t::return_t;using obj_t = typename forge_t::obj_t;using arginfo_t = typename forge_t::arginfo_t;arginfo_t arginfo;tuple_t tuple;xLB_ami ami; ami.top = lua_gettop(L);ami.next_index = 1;xLB_loadobj<obj_t, LVER>::go(L, tuple, ami, arginfo);if (!xLB_badtype(ami)) {ami.default_count = DFER::go(tuple);ami.arg_count = arg_t::size;xLB_fver<LVER, tuple_t, idxer_t, vter_arg_t>::go(L, tuple, arginfo, ami);}if (xLB_badtype(ami)) {return luaL_argerror(L, ami.next_index, ami.extmsg);}ami.return_count = 0;xLB_caler::template xLB_tir<return_t, obj_t, FT,idxer_t,VPER, arg_t, RNER, PPER>::go(L, ami, f, tuple);PTER::template xLB_tir<RIER,tuple_t,PPER>::go(L, tuple, arginfo, ami.return_count);return ami.return_count;}/*---------------------------------------------------------------------------xLB_getter-----------------------------------------------------------------------------*/template<class PT> struct xLB_proptype { };template<class P, class Tx> struct xLB_proptype<P Tx::*> {using obj_t = Tx;using property_t = P;};template<class PT, PT property, class PPER>int xLB_getter(lua_State* L) { // t,kusing forge_t = xLB_proptype<PT>;using obj_t = typename forge_t::obj_t;using property_t = typename forge_t::property_t;// use wrapper to get obj pointerusing wrap_t = xLB_ludwrap<obj_t>;auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));auto obj = wrap->ptr(); assert(obj != nullptr);auto return_count = 0;if (obj) {xLB_arginfo ai;PPER::template xLB_tir<typename std::remove_reference<property_t>::type>::go(L, 1, (*obj).*property, ai, return_count);} else {printf("xLB_getdynamicud failed.\n");}return return_count;}template<class PT, PT property, class VTER, class LVER>int xLB_setter(lua_State* L) { // t,k,vusing forge_t = xLB_proptype<PT>;using obj_t = typename forge_t::obj_t;using property_t = typename forge_t::property_t;// use wrapper to get obj pointerusing wrap_t = xLB_ludwrap<obj_t>;auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));auto obj = wrap->ptr(); assert(obj != nullptr);auto return_count = 0;if (obj) {xLB_ami ami; ami.top = lua_gettop(L);ami.obj = obj;ami.next_index = 3;using vter_t = typename VTER::template xLB_tir<property_t>::type;std::tuple<vter_t> tuple;LVER::template xLB_tir<vter_t, property_t>::go(L, std::get<0>(tuple), tuple, ami);(*obj).*property = std::get<0>(tuple);} else {printf("xLB_getdynamicud failed.\n");}return return_count;}/*---------------------------------------------------------------------------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, int parent_table_index = 0) {xLB_xotrait<T>::register_(L, parent_table_index);}template<typename T>void xLB_xoglobal(lua_State* L, T* obj, const char* name) {xLB_wrapxo(L, obj);lua_setglobal(L, name);}/*---------------------------------------------------------------------------xLB_xomethod-----------------------------------------------------------------------------*/template<typename T> struct xLB_xomethod {using type = int (*)(lua_State*, T*);};template<typename R, typename T, typename... A>struct xLB_xomethod<R (T::*)(A...) > {using type = R(T::*)(A...);};template<typename R, typename T, typename... A>struct xLB_xomethod<R (T::*)(A...) const > {using type = R(T::*)(A...) const;};template<typename T, typename xLB_xomethod<T>::type f>int xLB_xomethod_simple(lua_State* L) {int rc = 0;T* obj = xLB_getxo<T>(L, 1);if (obj) rc = f(L, obj);return rc;}/*---------------------------------------------------------------------------luavar_info-----------------------------------------------------------------------------*/struct luavar_info {enum { readonly, readwrite, writeonly, function };int type;lua_CFunction getter;lua_CFunction setter;};/*---------------------------------------------------------------------------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<> std::vector<const char*> xLB_xobase<xo_t>::super_names=std::vector<const char*>(); \template<> std::vector<luaL_reg> xLB_xobase<xo_t>::rg_type={{nullptr,nullptr}}; \template<> std::vector<luaL_reg> xLB_xobase<xo_t>::rg_meta={{nullptr,nullptr}}; \template<> std::unordered_map<string, luavar_info> xLB_xobase<xo_t>::property_map={}; \#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_xotrait(); \}; \xLB_xotrait<xo_t>::xLB_xotrait() \/*---------------------------------------------------------------------------xLB_xotrait-----------------------------------------------------------------------------*/template<typename T> struct xLB_xotrait {};/*---------------------------------------------------------------------------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 std::vector<const char*> super_names;static regs_t rg_meta;static regs_t rg_type;static std::unordered_map<string, luavar_info> property_map;static inline void regfunc(const char fn[], lua_CFunction f) {property_map[fn] = { luavar_info::function, f, nullptr };}static int index_handler(lua_State* L) { //__index(t,k)auto var_name = luaL_optlstring(L, 2, "", nullptr);auto iter = property_map.find(var_name);int nfound = 0;if (iter != property_map.end()) {switch (iter->second.type) {case luavar_info::readonly:case luavar_info::readwrite:iter->second.getter(L);nfound = 1;break;case luavar_info::function:lua_pushcfunction(L, iter->second.getter);nfound = 1;break;}}if (0 == nfound) {nfound = xLB_util::search_getter(L, meta_name, super_names);}return nfound;}static int newindex_handler(lua_State* L) { // __newindex(t,k,v)auto var_name = luaL_optlstring(L, 2, "", nullptr);auto iter = property_map.find(var_name);auto top = lua_gettop(L);int nfound = 0;if (iter != property_map.end()) {switch (iter->second.type) {case luavar_info::writeonly:case luavar_info::readwrite:iter->second.setter(L);if (top == 4) { // meant called by search_setterlua_pushnumber(L, XLB_TRAP_FLAG);}nfound = 2;break;}}if (0 == nfound) {nfound = xLB_util::search_setter(L, meta_name, super_names);}if (2 == nfound) { // have found itif (4 == top) { nfound = 1; }else { nfound = 0; }} else {if (4 == top) { lua_pushnil(L); nfound = 1; }}return nfound;}static int tostring_handler(lua_State* L) {auto obj = xLB_getdynamicud<T>(L, 1);auto return_count = 1;if (obj) {lua_pushfstring(L, "xLB_object: 0x%p", obj);} else {lua_getglobal(L, "tostring");lua_pushvalue(L, 1);lua_pcall(L, 1, 1, 0);}return return_count;}template<class SUPER_XO> static void super() { super_names.push_back(xLB_xotrait<SUPER_XO>::meta_name); }template<lua_CFunction f> static void c(const char fn[]="new") { rg_type.insert(begin(rg_type), {fn,f});}template<typename...A> static inline T* xLB_newer(A...arg_metas) { return new T(arg_metas...); }static void destructor() { rg_meta.insert(begin(rg_meta), {"__gc", xLB_gcxo<T>});}template<typename xLB_xomethod<T>::type f> static void b(const char fn[]) { regfunc(fn, xLB_xomethod_simple<T, f>);}template<lua_CFunction f> static void b(const char fn[]) { regfunc(fn, f); }static inline void def(const char fn[], lua_CFunction f) { regfunc(fn, f); }static inline void constructor(const char fn[], lua_CFunction f) {rg_type.insert(begin(rg_type), {fn, f});}template<class PT, PT property, class PPER=xLB_pper>static inline void def_readonly(const char property_name[]) {property_map[property_name] = { luavar_info::readonly, xLB_getter<PT, property, PPER>,nullptr,};}template<class PT, PT property, class PPER=xLB_pper, class VTER=xLB_vter, class LVER=xLB_lver>static inline void def_readwrite(const char property_name[]) {property_map[property_name] = { luavar_info::readwrite, xLB_getter<PT, property, PPER>,xLB_setter<PT, property, VTER, LVER>,};}static void register_(lua_State* L, int parent_table_index = 0) {rg_meta.insert(begin(rg_meta), {"__index", &index_handler});rg_meta.insert(begin(rg_meta), {"__newindex", &newindex_handler});rg_meta.insert(begin(rg_meta), {"__tostring", &tostring_handler});xLB_util::newxometatable(L, meta_name, rg_meta, super_names);xLB_util::registertypetable(L, trait_t::type_name, rg_type, parent_table_index);}}; // end of xLB_xobase#endif // end of __XLB_H__




0 0
原创粉丝点击