#ifndef _LUA_METATABLE_H_ #define _LUA_METATABLE_H_ #include #include #define LUA_TINTEGER LUA_NUMTAGS + 1 #define LUA_TSTRINGA LUA_NUMTAGS + 2 #define LUA_TSTRINGW LUA_NUMTAGS + 3 struct MTField { size_t offset; size_t size; int type; MTField(size_t offset, size_t size, int type) : offset(offset), size(size), type(type) { } }; template class MT { private: static const char *name; static std::map fields; template static int GetType(R T::*) { return NULL; } template<> static int GetType(int T::*) { return LUA_TINTEGER; } template<> static int GetType(unsigned int T::*) { return LUA_TINTEGER; } template<> static int GetType(long T::*) { return LUA_TINTEGER; } template<> static int GetType(unsigned long T::*) { return LUA_TINTEGER; } template<> static int GetType(long long T::*) { return LUA_TINTEGER; } template<> static int GetType(unsigned long long T::*) { return LUA_TINTEGER; } template<> static int GetType(char* T::*) { return LUA_TSTRINGA; } template<> static int GetType(wchar_t* T::*) { return LUA_TSTRINGW; } template static R GetValue(const T *obj, size_t offset, size_t size) { R res; memcpy(&res, ((char*)obj) + offset, size); return res; } static int __new(lua_State *L) { T *obj = NULL; T **udata = NULL; int type = lua_type(L, 1); switch (type) { case LUA_TLIGHTUSERDATA: obj = (T*)MT::Load(L); if (obj == NULL) break; //case LUA_TNONE: udata = (T**)lua_newuserdata(L, sizeof(T*)); *udata = MT::Init(obj); //case LUA_TUSERDATA: // luaL_setmetatable(L, MT::name); // return 1; } lua_pushnil(L); return 1; } static int __index(lua_State *L) { T *obj = *(T**)luaL_checkudata(L, 1, MT::name); const char *key = lua_tostring(L, 2); auto it = fields.find(key); if (it == fields.end()) { lua_pushnil(L); return 1; } MTField *field = it->second; size_t offset = field->offset; size_t size = field->size; switch (field->type) { case LUA_TBOOLEAN: lua_pushboolean(L, GetValue(obj, offset, size)); break; case LUA_TINTEGER: lua_pushinteger(L, GetValue(obj, offset, size)); break; case LUA_TNUMBER: lua_pushnumber(L, GetValue(obj, offset, size)); break; case LUA_TSTRING: lua_pushstring(L, GetValue(obj, offset, size)); break; case LUA_TSTRINGA: lua_pushstring(L, ptrA(mir_utf8encode(GetValue(obj, offset, size)))); break; case LUA_TSTRINGW: lua_pushstring(L, ptrA(mir_utf8encodeW(GetValue(obj, offset, size)))); break; default: lua_pushnil(L); } return 1; } static int __gc(lua_State *L) { T** obj = (T**)luaL_checkudata(L, 1, MT::name); MT::Free(obj); return 0; } static T* Load(lua_State *L) { return (T*)lua_touserdata(L, 1); } static T* Init(T *val) { return val; } static void Free(T *obj) { obj = NULL; } public: MT(lua_State *L, const char *tname) { MT::name = tname; lua_pushcfunction(L, __new); lua_setglobal(L, MT::name); luaL_newmetatable(L, MT::name); lua_pushcfunction(L, __index); lua_setfield(L, -2, "__index"); } template MT& Field(R T::*M, const char *name, int type = LUA_TNONE, size_t size = sizeof(R)) { size_t offset = reinterpret_cast(&(((T*)0)->*M)); if (type == LUA_TNONE) type = GetType(M); if (type != LUA_TNONE) fields[name] = new MTField(offset, size, type); return *this; } }; template const char *MT::name; template std::map MT::fields; #endif //_LUA_METATABLE_H_