书接上一回,继续补充xlb的功能。这次修改代码的代码比添加功能的代码还多,完成后大致包括
添加绑定常量得等下一回继续。从C++调用lua这部分还没开始,还有许多功能需要实现,向luabind等学习,继续丰富其功能。xlb没有使用upvalue,纯模板编译时确定,因为还有许多功能未实现,现在仍不知道这会不会带来麻烦。
测试代码:
for k,v in pairs(clsA) do print(k,v); end objC: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)) do print(k,v); end print(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: 0040A128 clsC::override_ clsA::override_ clsC::override_ xLB_object: 0x0022FEC4 1234 333 1 base class clsB::b() method called xLB_object: 0x0022FEDB base class clsB::b() method called 111 __newindex function: 0040AFC4 __tostring function: 0040B150 xLB_meta xLB_clsA xLB_super table: 005D9B20 xLB_ancient table: 005D9AF8 __gc function: 0040A860 __index function: 0040AE64 xLB_object: 0x0022FED0 obj:NoReturn[a=555] obj:NoReturn[a=8888] clsA::Add(1,2):3 called clsA::Add(int,int,int):1+2+3=6 called clsA::Add(int,int,int):1+2+3=6 called g(54321) 54323 foo called. foo called: 1 obj: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 clsA struct 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
#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; }
#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 alias using 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 itself lua_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 userdata lua_pcall(L, 2, 1, 0); lua_remove(L, -2); // remove metatable if (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 metatable lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_pushvalue(L, 3); // Notes: push additional argument(XLB_TRAP_FLAG) for __newindex calling lua_pushnumber(L, XLB_TRAP_FLAG); // Note: manual call __newindex, instead using lua_settable // since the value one the 1 index must be userdata lua_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 value if (!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 value if (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>0 return wp->ptr(); } else { return nullptr; } } /*--------------------------------------------------------------------------- xLB_dfer function 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==1 if (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_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, 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_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> { 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_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, 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_vper change type of value according to parameter‘s type for calling function -----------------------------------------------------------------------------*/ struct xLB_vper { template<class To, class From> struct xLB_tir { static inline const To& go(const From& tuple_val) { return tuple_val; } }; }; template<class T>struct xLB_vper::xLB_tir<T*, T*> { static inline T* go(T* tuple_val) { return tuple_val; } }; template<>struct xLB_vper::xLB_tir<int&, int> { static inline int& go(int& tuple_val) { return tuple_val; } }; template<>struct xLB_vper::xLB_tir<int*, int> { static inline int* go(int& tuple_val) { return &tuple_val; } }; /*--------------------------------------------------------------------------- xLB_vter decide type of value for saving data come from lua_State -----------------------------------------------------------------------------*/ struct xLB_vter { template<class PARAM_TYPE> struct xLB_tir { using type = PARAM_TYPE; static_assert(std::is_pod<PARAM_TYPE>::value, "Warning: xLB_vter no implement\n"); }; }; template<class PARAM_TYPE> struct xLB_vter::xLB_tir<PARAM_TYPE&> { using type = typename xLB_vter::xLB_tir<PARAM_TYPE>::type; }; template<> struct xLB_vter::xLB_tir<int*> { using type = int; }; template<> struct xLB_vter::xLB_tir<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_cfunction overload 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_cfunction overload 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_cfunction normal 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,k using 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 pointer using 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,v using 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 pointer using 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_setter lua_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 it if (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__
20140218-lua binder另一只轮子的雏形(2014-01-02 20:08)
原文:http://blog.csdn.net/alga_1/article/details/19421255