书接上一回,继续补充xlb的功能。这次修改代码的代码比添加功能的代码还多,完成后大致包括
- 添加了支持overload和override函数绑定,支持绑定属性;
- 添加了构造函数绑定,释构函数绑定前面已经实现了,这次是把名字修改了;
- 修改函数参数提取过程,支持非一对一提取,即是一个函数形参可以从lua_State中提取N个参数(0<=N<=lua_gettop(L)),不过这一功能的具体用途还不是很清晰;
- 添加绑定函数执行过程错误提示;
- 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
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 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__