#ifndef OILACCESS_H #define OILACCESS_H extern "C" { #include #include } namespace OiLAccess { // // Template implementation auxilary functions // extern const char *CLASS_REGISTRY; extern const char *OBJECT_REGISTRY; int lua_tableinsert(lua_State *L, int table); void lua_pushregistry(lua_State *L, const char *name); // // Template declarations // template class Exported; template class ExportedObject { private: friend class Exported; Exported *exportedClass; Actual *actualObject; int registerIndex; ExportedObject(Exported *expCls, Actual *instance); ~ExportedObject(); public: Actual *getObject(); void pushOnStack(); }; template class Exported { public: typedef int (Actual::*PMethod)(lua_State*); typedef struct Method { const char* name; PMethod method; }; typedef ExportedObject Object; Exported(lua_State *state, Method *methods, lua_CFunction func); ~Exported(); Object *newObject(Actual *instance); private: friend class ExportedObject; lua_State *luaState; Method *methodList; int registerIndex; int registerObject(Actual *object); void unregisterObject(int index); void pushObject(int index); }; }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// namespace OiLAccess { // // template ExportedObject member implementation // template ExportedObject::ExportedObject(Exported *expCls, Actual *instance) : exportedClass(expCls), actualObject(instance), registerIndex(exportedClass->registerObject(actualObject)) {}; template ExportedObject::~ExportedObject() { exportedClass->unregisterObject(registerIndex); } template Actual* ExportedObject::getObject() { return actualObject; } template void ExportedObject::pushOnStack() { exportedClass->pushObject(registerIndex); } // // auxilary template functions // template void lua_boxmember( lua_State *L, typename Exported::PMethod member ) { int pointer_size = sizeof(typename Exported::PMethod); void *userdata = lua_newuserdata(L, pointer_size); typename Exported::PMethod *box = static_cast< typename Exported::PMethod* >(userdata); *box = member; } template typename Exported::PMethod lua_unboxmember( lua_State *L, int index ) { void *userdata = lua_touserdata(L, index); typename Exported::PMethod *box = static_cast< typename Exported::PMethod* >(userdata); return *box; } //-------------------------------------------------------------------------- template void lua_boxobject( lua_State *L, Actual *object ) { int pointer_size = sizeof(Actual*); void *userdata = lua_newuserdata(L, pointer_size); Actual **box = static_cast< Actual** >(userdata); *box = object; } template Actual *lua_unboxobject( lua_State *L, int index ) { void *userdata = lua_touserdata(L, index); Actual **box = static_cast< Actual** >(userdata); return *box; } //-------------------------------------------------------------------------- template void lua_newcppclass(lua_State *L, typename Exported::Method *methods, lua_CFunction func) { lua_newtable(L); int metatable = lua_gettop(L); for (int i = 0; methods[i].name; ++i) { lua_pushstring(L, methods[i].name); lua_boxmember(L, methods[i].method); lua_pushcclosure(L, func, 1); lua_rawset(L, metatable); } lua_pushliteral(L, "__index"); lua_pushvalue(L, metatable); lua_rawset(L, metatable); } //-------------------------------------------------------------------------- template int lua_wrapper(lua_State *L) { int index = lua_upvalueindex(1); luaL_checktype(L, 1, LUA_TUSERDATA); typename Exported::PMethod method = lua_unboxmember(L, index); Actual *object = lua_unboxobject(L, 1); lua_remove(L, 1); return ((*object).*method)(L); } // // template Exported member implementation // template Exported::Exported(lua_State *state, typename Exported::Method *methods, lua_CFunction func) : luaState(state), methodList(methods) { lua_pushregistry(luaState, CLASS_REGISTRY); lua_newcppclass(luaState, methodList, func); registerIndex = lua_tableinsert(luaState, -2); lua_pop(luaState, 1); } template Exported::~Exported() { } //-------------------------------------------------------------------------- template int Exported::registerObject(Actual *object) { lua_pushregistry(luaState, OBJECT_REGISTRY); // OBJECTS lua_boxobject(luaState, object); // OBJECTS, object lua_pushregistry(luaState, CLASS_REGISTRY); // OBJECTS, object, CLASSES lua_pushnumber(luaState, registerIndex); // OBJECTS, object, CLASSES, classIndex lua_rawget(luaState, -2); // OBJECTS, object, CLASSES, classMeta lua_setmetatable(luaState, -3); // OBJECTS, object, CLASSES lua_pop(luaState, 1); // OBJECTS, object int result = lua_tableinsert(luaState, -2); // OBJECTS lua_pop(luaState, 1); // return result; } template void Exported::unregisterObject(int index) { lua_pushregistry(luaState, OBJECT_REGISTRY); // OBJECTS lua_pushnumber(luaState, index); // OBJECTS, index lua_rawget(luaState, -2); // OBJECTS, object lua_pushnil(luaState); // OBJECTS, object, nil lua_setmetatable(luaState, -2); // OBJECTS, object lua_pop(luaState, 1); // OBJECTS lua_pushnumber(luaState, index); // OBJECTS, index lua_pushnil(luaState); // OBJECTS, index, nil lua_rawset(luaState, -2); // OBJECTS lua_pop(luaState, 1); // } template void Exported::pushObject(int index) { lua_pushregistry(luaState, OBJECT_REGISTRY); // OBJECTS lua_pushnumber(luaState, index); // OBJECTS, index lua_rawget(luaState, -2); // OBJECTS, object lua_remove(luaState, -2); // object } template typename Exported::Object *Exported::newObject(Actual *instance) { return new typename Exported::Object(this, instance); } }; #endif /* OILACCESS_H */