diff options
Diffstat (limited to 'source/3rd-party/Luax/luax_class.inl')
-rw-r--r-- | source/3rd-party/Luax/luax_class.inl | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/source/3rd-party/Luax/luax_class.inl b/source/3rd-party/Luax/luax_class.inl new file mode 100644 index 0000000..028d4f9 --- /dev/null +++ b/source/3rd-party/Luax/luax_class.inl @@ -0,0 +1,550 @@ +namespace Luax +{ + + //---------------------------------------------------------------------------------------------------------------- + // ӿ + + /// + /// ԲͬͣͨGetLuaClassName࣬GetClassNameᱻǣָluax_c_getupvalue + /// + template<typename T> + int LuaxNativeClass<T>::l_GetClassName(lua_State* L) + { + LUAX_SETUP(L, "*"); + + cc8* type = T::GetLuaxClassName(); + state.Push(type); + return 1; + } + + //---------------------------------------------------------------------------------------------------------------- + + /// + /// עṤ͵еԱ + /// + template<typename T> + void LuaxNativeClass<T>::RegisterLuaxClass(LuaxState& state) + { + luaL_Reg regTable[] = { + { "GetClass", l_GetClass }, + { "GetClassName", l_GetClassName }, + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + /// + /// ijԱעclass table + /// + template<typename T> + void LuaxNativeClass<T>::RegisterLuaxFactoryClass(LuaxState& state) + { + luaL_Reg regTable[] = { + { "GetRefTable", l_GetRefTable }, + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + /// + /// ijԱעclass table + /// + template<typename T> + void LuaxNativeClass<T>::RegisterLuaxSingletonClass(LuaxState& state) + { + luaL_Reg regTable[] = { + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + template<typename T> + void LuaxNativeClass<T>::PushLuaxClassTable(LuaxState& state) + { + assert(mClassTable); + + mClassTable.PushRef(state); + } + + template<typename T> + void LuaxNativeClass<T>::SetLuaxClassTableRef(LuaxState& state, int idx) + { + mClassTable.SetRef(state, idx); + } + + template<typename T> + LuaxNativeClass<T>::LuaxNativeClass() + { + } + + template<typename T> + LuaxNativeClass<T>::~LuaxNativeClass() + { + } + + template<typename T> + template<typename U> + void LuaxNativeClass<T>::LuaRetain(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<u32>(-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<typename T> + template<typename U> + void LuaxNativeClass<T>::LuaRelease(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<u32>(-1, 0); // get the count (or 0) + lua_pop(state, 1); // pop the old count + + if (count == 0) 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 + } + } + } + + template<typename T> + bool LuaxNativeClass<T>::PushLuaxUserdata(LuaxState& state) + { + assert(!T::IsLuaxClassSingleton()); + if (!mUserdata) + { + BindToLua(state); + return true; + } + return mUserdata.PushRef(state); + } + + template<typename T> + bool LuaxNativeClass<T>::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; + } + } + } + state.SetTop(top); + lua_pushnil(state); + return false; + } + + template<typename T> + bool LuaxNativeClass<T>::PushLuaxRefTable(LuaxState& state) + { + // Singleton + if (T::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 tablemember tableclass table + /// ref table kvǿtableuserdataüͨuserdataΪkeyΪvalueԼԱ + /// member table luaʵijԱ + /// class table б͵ʵеĺ + /// + template<typename T> + void LuaxNativeClass<T>::BindToLua(LuaxState& state) + { + // ܰuserdata + assert(!T::IsLuaxClassSingleton()); + assert(!mUserdata); + + // userdataջ + state.PushPtrUserData(this); + + lua_newtable(state); // ref tableluaʣC + lua_newtable(state); // member tableluaдĶԱ + 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 + lua_pushcfunction(state, l___tostring); + lua_setfield(state, refTable, "__tostring"); + + // 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_pushcfunction(state, l___gc); + lua_setfield(state, refTable, "__gc"); + + // Ԫ + 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ãͨPushLuaUserdatalua + mUserdata.SetRef(state, -1); + assert(mUserdata); + } + + /// + /// Աù + /// + template<typename T> + void LuaxNativeClass<T>::SetMemberRef(LuaxState& state, LuaxMemberRef& memRef, int idx) + { + ClearMemberRef(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<typename T> + bool LuaxNativeClass<T>::PushMemberRef(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<typename T> + void LuaxNativeClass<T>::ClearMemberRef(LuaxState& state, LuaxMemberRef& memRef) + { + if (memRef) + { + if (PushLuaxRefTable(state)) + { + luaL_unref(state, -1, memRef.refID); + state.Pop(); // ref table + } + memRef.refID = LUA_NOREF; + } + } + + //-------------------------------------------------------------------------------------------------------------- + + /// + /// ͷŹʵ + /// + template<typename T> + int LuaxNativeClass<T>::l___gc(lua_State* L) + { + LUAX_SETUP(L, "U"); + T* self = state.GetLuaUserdata<T>(1); + delete self; + return 0; + } + + /// + /// ʽ: + /// ַ + /// + template<typename T> + int LuaxNativeClass<T>::l___tostring(lua_State* L) + { + // params: + // 1: userdata + + LUAX_STATE(L); + T* self = state.GetLuaUserdata<T>(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<cc8*>(-1, ""); + } + else + { + classname = T::GetLuaxClassName(); + } + lua_pushfstring(L, "%s: %p", classname, self); + return 1; + } + return 0; + } + +#if LUAX_ENABLE_NATIVE_EXTEND + /// + /// ࣬luaijԱΪƣDZ֤userdataͳһNative classṩCtor֧֣ + /// nativeʵ崴ʹCtorгʼӵкͻһNewбnativeһ͡ + /// + template<typename T> + int LuaxNativeClass<T>::l_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, l_ExtendFactory, 1); + lua_setfield(L, -2, "Extend"); + + // .New() + lua_pushvalue(L, inheritClass); + lua_getfield(L, baseClass, "New"); + lua_pushcclosure(L, 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<typename T> + int LuaxNativeClass<T>::l_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, 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<typename T> + int LuaxNativeClass<T>::l_GetClass(lua_State* L) + { + LUAX_STATE(L); + if (!mClassTable) + lua_pushnil(L); + else + mClassTable.PushRef(state); + return 1; + } + + template<typename T> + int LuaxNativeClass<T>::l_GetRefTable(lua_State* L) + { + LUAX_STATE(L); + T* self = state.GetLuaUserdata<T>(1); + bool success = self->PushLuaxRefTable(state); + if (!success) + lua_pushnil(L); + return 1; + } + + template<typename T> + int LuaxNativeClass<T>::l_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); + + // ԵCtor + lua_getfield(L, lua_upvalueindex(1), "Ctor"); + + 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<typename T> LuaxStrongRef LuaxNativeClass<T>::mClassTable; // class table + template<typename T> LuaxStrongRef LuaxNativeClass<T>::mSingletonRefTable; // + +}
\ No newline at end of file |