summaryrefslogtreecommitdiff
path: root/source/3rd-party/Luax/luax_class.inl
diff options
context:
space:
mode:
Diffstat (limited to 'source/3rd-party/Luax/luax_class.inl')
-rw-r--r--source/3rd-party/Luax/luax_class.inl550
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 table޷luaʣ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