namespace Luax { //--------------------------------------------------------------------------------// /// /// 对不同类型,通过调用GetLuaClassName获得类型名,如果是派生类,GetClassName会被覆盖,指向luax_c_getupvalue。 /// template int LuaxNativeClass::_GetClassName(lua_State* L) { LUAX_SETUP(L, "*"); cc8* type = TYPE::GetLuaxClassName(); state.Push(type); return 1; } //--------------------------------------------------------------------------------// /// /// 注册工厂和单例共有的类成员 /// template void LuaxNativeClass::RegisterLuaxClassShared(LuaxState& state) { luaL_Reg regTable[] = { { "GetClass", _GetClass }, { "GetClassName", _GetClassName }, { NULL, NULL } }; state.RegisterMethods(regTable); } /// /// 工厂类的成员,注册在class table /// template void LuaxNativeClass::RegisterLuaxFactoryClass(LuaxState& state) { luaL_Reg regTable[] = { { "GetRefTable", _GetRefTable }, { NULL, NULL } }; state.RegisterMethods(regTable); } /// /// 单例类的成员,注册在class table /// template void LuaxNativeClass::RegisterLuaxSingletonClass(LuaxState& state) { luaL_Reg regTable[] = { { NULL, NULL } }; state.RegisterMethods(regTable); } template void LuaxNativeClass::PushLuaxClassTable(LuaxState& state) { assert(mClassTable); mClassTable.PushRef(state); } template void LuaxNativeClass::SetLuaxClassTableRef(LuaxState& state, int idx) { mClassTable.SetRef(state, idx); } template LuaxNativeClass::LuaxNativeClass() : mWatchDog() #if LUAX_PROFILER , mSafer(false) #endif { } template LuaxNativeClass::~LuaxNativeClass() { } #if LUAX_PROFILER template void LuaxNativeClass::operator delete(void* pdead, size_t size) { if (pdead == nullptr) return; // 堆上创建的实例必须使用Release释放。 TYPE* p = static_cast(pdead); assert(p->mSafer); ::operator delete(pdead, size); } #endif template void LuaxNativeClass::Retain() { ++mWatchDog.mNativeRef; } template void LuaxNativeClass::Release() { if (mWatchDog.mNativeRef > 0) --mWatchDog.mNativeRef; if (mWatchDog) { #if LUAX_PROFILER mSafer = true; #endif delete this; } } template template void LuaxNativeClass::LuaxRetain(LuaxState& state, U* userdata) { if (PushLuaxRefTable(state)) { if (userdata->PushLuaxUserdata(state)) { lua_pushvalue(state, -1); // copy the userdata lua_gettable(state, -3); // get the count (or nil) u32 count = state.GetValue(-1, 0); // get the count (or 0) lua_pop(state, 1); // pop the old count lua_pushnumber(state, count + 1); // push the new count lua_settable(state, -3); // save it in the table: reftable[userdata] = count } } } template template void LuaxNativeClass::LuaxRelease(LuaxState& state, U* userdata) { if (PushLuaxRefTable(state)) { if (userdata->PushLuaxUserdata(state)) { lua_pushvalue(state, -1); // copy the userdata lua_gettable(state, -3); // get the count (or nil) u32 count = state.GetValue(-1, 0); // get the count (or 0) lua_pop(state, 1); // pop the old count // no such reference if (count == 0) { state.Pop(2); // userdata, reftable return; // nothing to do } if (count > 1) { lua_pushnumber(state, count - 1); // push the new count } else { lua_pushnil(state); // maybe cause gc } lua_settable(state, -3); // save it in the table state.Pop(1); // reftable return; } state.Pop(2); // nil, reftable return; } } template bool LuaxNativeClass::PushLuaxUserdata(LuaxState& state) { assert(!TYPE::IsLuaxClassSingleton()); if (!mUserdata) { BindToLua(state); return true; } return mUserdata.PushRef(state); } template bool LuaxNativeClass::PushLuaxMemberTable(LuaxState& state) { int top = state.GetTop(); if (this->PushLuaxUserdata(state)) { if (lua_getmetatable(state, -1)) // ref table { lua_replace(state, -2); if (lua_getmetatable(state, -1)) // member table { lua_replace(state, -2); return true; } } } lua_settop(state, top); lua_pushnil(state); return false; } template bool LuaxNativeClass::PushLuaxRefTable(LuaxState& state) { // Singleton if (TYPE::IsLuaxClassSingleton()) { if (!this->mSingletonRefTable) { lua_newtable(state); this->mSingletonRefTable.SetRef(state, -1); // strong ref to member table won't be garbage collected } else { this->mSingletonRefTable.PushRef(state); } return true; } // Factory else { if (this->PushLuaxUserdata(state)) { if (lua_getmetatable(state, -1)) { lua_replace(state, -2); return true; } } } return false; } /// /// 创建userdata,并以此添加ref table,member table和class table。 /// ref table 是kv强引用table,保存对其他userdata的引用计数(通过userdata作为key, /// 计数为value),以及成员引用 /// member table 保存lua创建的实例的成员 /// class table 所有本类型的实例共有的函数表 /// /// BindToLua只会在第一次注册给Lua虚拟机时调用。 /// template void LuaxNativeClass::BindToLua(LuaxState& state) { // 单例不能绑定userdata assert(!TYPE::IsLuaxClassSingleton()); assert(!mUserdata); /// /// 创建userdata并留在栈顶,注意地址要转换为TYPE*,直接用this可能会导致多重继承的类丧失多态。 /// 如果直接传this进去,在多重继承情况下,是拿不到另一头的虚函数表的。所以这里需要将this /// 转换为整个对象的低地址,这样可以拿到另一个基类的虚函数表,通过另一个基类实现多态。 /// TYPE* p = static_cast(this); state.PushPtrUserdata(p); lua_newtable(state); // ref table,无法在lua处访问,用来管理C对象的生命周期 lua_newtable(state); // member table,lua中创建的对象成员都保存在这里 PushLuaxClassTable(state); // class table // stack: // -1: class table // -2: member table // -3: ref table // -4: userdata int top = state.GetTop(); int memberTable = top - 1; int refTable = top - 2; // ref table 注册 __tostring 和 __gc lua_pushcfunction(state, __tostring); lua_setfield(state, refTable, "__tostring"); lua_pushcfunction(state, __gc); lua_setfield(state, refTable, "__gc"); // ref table 的 __index 和 __newindex 设为 member table lua_pushvalue(state, memberTable); lua_setfield(state, refTable, "__index"); lua_pushvalue(state, memberTable); lua_setfield(state, refTable, "__newindex"); // 设置元表 lua_setmetatable(state, -2); // class is meta of member lua_setmetatable(state, -2); // member is meta of ref lua_setmetatable(state, -2); // ref is meta of userdata // 设置一个userdata的弱引用,方便通过PushLuaUserdata方法返回lua对象 mUserdata.SetRef(state, -1); assert(mUserdata); // 增加一个虚拟机引用,在GC时-1 ++mWatchDog.mVMRef; #if LUAX_PROFILER mRefVMs.insert(state.GetVM()); #endif } /// /// 成员引用管理 /// template void LuaxNativeClass::SetLuaxMemberRef(LuaxState& state, LuaxMemberRef& memRef, int idx) { ClearLuaxMemberRef(state, memRef); if (!lua_isnil(state, idx)) { idx = state.AbsIndex(idx); if (PushLuaxRefTable(state)) { lua_pushvalue(state, idx); memRef.refID = luaL_ref(state, -2); state.Pop(); // ref table } } } template bool LuaxNativeClass::PushLuaxMemberRef(LuaxState& state, LuaxMemberRef& memRef) { if (memRef) { if (PushLuaxRefTable(state)) { lua_rawgeti(state, -1, memRef.refID); lua_replace(state, -2); // ref table if (lua_isnil(state, -1)) goto failed; return true; } } lua_pushnil(state); failed: memRef.refID = LUA_NOREF; return false; } template bool LuaxNativeClass::PushLuaxMemberRef(LuaxState& state, int refID) { if (PushLuaxRefTable(state)) { lua_rawgeti(state, -1, refID); lua_replace(state, -2); // ref table if (lua_isnil(state, -1)) goto failed; return true; } lua_pushnil(state); failed: return false; } template void LuaxNativeClass::ClearLuaxMemberRef(LuaxState& state, LuaxMemberRef& memRef) { if (memRef) { if (PushLuaxRefTable(state)) { luaL_unref(state, -1, memRef.refID); state.Pop(); // ref table } memRef.refID = LUA_NOREF; } } //--------------------------------------------------------------------------------// /// /// 释放工厂创建的实例 /// template int LuaxNativeClass::__gc(lua_State* L) { LUAX_STATE(L); TYPE* self = state.GetUserdata(1); assert(self); #if LUAX_PROFILER std::cout << "Luax: GC<" << TYPE::GetLuaxClassName() << ">\n"; #endif if(self->mWatchDog.mVMRef > 0) --self->mWatchDog.mVMRef; self->Release(); return 0; } /// /// 输出格式如下: /// 地址 类名 /// template int LuaxNativeClass::__tostring(lua_State* L) { // params: // 1: userdata LUAX_STATE(L); TYPE* self = state.GetUserdata(1); if (self) { cc8* classname = ""; lua_getfield(state, 1, "GetClassName"); if (state.IsType(-1, LUA_TFUNCTION)) { lua_pushvalue(L, 1); // userdata state.Call(1, 1); // 派生类的GetClassName函数 classname = state.GetValue(-1, ""); } else { classname = TYPE::GetLuaxClassName(); } lua_pushfstring(L, "%s: %p", classname, self); return 1; } return 0; } #if LUAX_ENABLE_NATIVE_EXTEND /// /// 派生出子类,在lua里对派生类的成员和行为进行重新设计,但是保证了userdata的统一。Native class的派生提供__init支持,在 /// native实体创建后可以使用__init进行初始化,派生类拥有和基类一样的New参数列表,且native对象是一样的类型。 /// template int LuaxNativeClass::_ExtendFactory(lua_State* L) { // upvalues: // 1: base class // params: // 1: class name int baseClass = lua_upvalueindex(1); lua_newtable(L); // class table int inheritClass = lua_gettop(L); // .GetClassName() cc8* type = lua_tostring(L, 1); lua_pushstring(L, type); lua_pushcclosure(L, luax_c_getupvalue, 1); lua_setfield(L, -2, "GetClassName"); // .GetClass() lua_pushvalue(L, inheritClass); lua_pushcclosure(L, luax_c_getupvalue, 1); lua_setfield(L, -2, "GetClass"); // .Extend() lua_pushvalue(L, inheritClass); lua_pushcclosure(L, _ExtendFactory, 1); lua_setfield(L, -2, "Extend"); // .New() lua_pushvalue(L, inheritClass); lua_getfield(L, baseClass, "New"); lua_pushcclosure(L, _New, 2); lua_setfield(L, -2, "New"); // __base = baseClass lua_pushvalue(L, baseClass); lua_setfield(L, -2, "__base"); // __index = inheritClass lua_pushvalue(L, inheritClass); lua_setfield(L, -2, "__index"); // metatable is baseClass lua_pushvalue(L, baseClass); lua_setmetatable(L, inheritClass); return 1; } template int LuaxNativeClass::_ExtendSingleton(lua_State* L) { // upvalues: // 1: base class // params: // 1: class name int baseClass = lua_upvalueindex(1); lua_newtable(L); // class name int inheritClass = lua_gettop(L); // .GetClassName() cc8* type = lua_tostring(L, 1); lua_pushstring(L, type); lua_pushcclosure(L, luax_c_getupvalue, 1); lua_setfield(L, -2, "GetClassName"); // .GetClass() lua_pushvalue(L, inheritClass); lua_pushcclosure(L, luax_c_getupvalue, 1); lua_setfield(L, -2, "GetClass"); // .Extend() lua_pushvalue(L, inheritClass); lua_pushcclosure(L, _ExtendFactory, 1); lua_setfield(L, -2, "Extend"); // __base = baseClass lua_pushvalue(L, baseClass); lua_setfield(L, -2, "__base"); // __index = inheritClass lua_pushvalue(L, inheritClass); lua_setfield(L, -2, "__index"); // metatable is baseClass lua_pushvalue(L, baseClass); lua_setmetatable(L, inheritClass); return 1; } #endif /*LUAX_ENABLE_NATIVE_EXTEND*/ template int LuaxNativeClass::_GetClass(lua_State* L) { LUAX_STATE(L); if (!mClassTable) lua_pushnil(L); else mClassTable.PushRef(state); return 1; } template int LuaxNativeClass::_GetRefTable(lua_State* L) { LUAX_STATE(L); TYPE* self = state.GetUserdata(1); bool success = self->PushLuaxRefTable(state); if (!success) lua_pushnil(L); return 1; } template int LuaxNativeClass::_New(lua_State* L) { LUAX_STATE(L); // upvalues: // 1: class table // 2: original New() // stack: // -1~-n: args int n = lua_gettop(L); // n args lua_pushvalue(L, lua_upvalueindex(2)); if (state.IsType(-1, LUA_TFUNCTION)) { // stack: // -1: New // -2~-1-n: args state.PushValues(-1 - n, n); // stack: // -1~-n: args // -n-1: New // -n-2~-1-2n: args state.Call(n, 1); // stack: // -1: userdata // -2~-1-n: args // reset member table's metatable to class table if (state.IsType(-1, LUA_TUSERDATA)) { if (lua_getmetatable(L, -1)) // ref table { if (lua_getmetatable(L, -1)) // member table { lua_pushvalue(L, lua_upvalueindex(1)); // class table lua_setmetatable(L, -2); state.Pop(); // member table } state.Pop(); // ref table } // stack: // -1: userdata // -2~-1-n: args int args = state.AbsIndex(-1 - n); // 尝试调用__init函数 lua_getfield(L, lua_upvalueindex(1), "__init"); if (state.IsType(-1, LUA_TFUNCTION)) { lua_pushvalue(L, -2); // userdata state.PushValues(args, n); state.Call(n + 1, 0); } else state.Pop(); } return 1; } return 0; } template LuaxStrongRef LuaxNativeClass::mClassTable; // class table template LuaxStrongRef LuaxNativeClass::mSingletonRefTable; // 单例 }