From 1497dccd63a84b7ee2b229b1ad9c5c02718f2a78 Mon Sep 17 00:00:00 2001 From: chai Date: Tue, 19 Mar 2019 23:06:27 +0800 Subject: *rename --- source/3rd-party/Luax/luax.h | 14 + source/3rd-party/Luax/luax_cfunctions.cpp | 19 + source/3rd-party/Luax/luax_cfunctions.h | 25 + source/3rd-party/Luax/luax_class.cpp | 243 ++++++++++ source/3rd-party/Luax/luax_class.hpp | 176 +++++++ source/3rd-party/Luax/luax_class.inl | 550 ++++++++++++++++++++++ source/3rd-party/Luax/luax_config.h | 60 +++ source/3rd-party/Luax/luax_context.cpp | 29 ++ source/3rd-party/Luax/luax_context.h | 36 ++ source/3rd-party/Luax/luax_enum.cpp | 67 +++ source/3rd-party/Luax/luax_enum.h | 38 ++ source/3rd-party/Luax/luax_memberref.cpp | 16 + source/3rd-party/Luax/luax_memberref.h | 27 ++ source/3rd-party/Luax/luax_ref.cpp | 69 +++ source/3rd-party/Luax/luax_ref.h | 62 +++ source/3rd-party/Luax/luax_reftable.cpp | 120 +++++ source/3rd-party/Luax/luax_reftable.h | 67 +++ source/3rd-party/Luax/luax_runtime.cpp | 89 ++++ source/3rd-party/Luax/luax_runtime.h | 59 +++ source/3rd-party/Luax/luax_state.cpp | 737 ++++++++++++++++++++++++++++++ source/3rd-party/Luax/luax_state.h | 238 ++++++++++ source/3rd-party/Luax/luax_state.inl | 140 ++++++ 22 files changed, 2881 insertions(+) create mode 100644 source/3rd-party/Luax/luax.h create mode 100644 source/3rd-party/Luax/luax_cfunctions.cpp create mode 100644 source/3rd-party/Luax/luax_cfunctions.h create mode 100644 source/3rd-party/Luax/luax_class.cpp create mode 100644 source/3rd-party/Luax/luax_class.hpp create mode 100644 source/3rd-party/Luax/luax_class.inl create mode 100644 source/3rd-party/Luax/luax_config.h create mode 100644 source/3rd-party/Luax/luax_context.cpp create mode 100644 source/3rd-party/Luax/luax_context.h create mode 100644 source/3rd-party/Luax/luax_enum.cpp create mode 100644 source/3rd-party/Luax/luax_enum.h create mode 100644 source/3rd-party/Luax/luax_memberref.cpp create mode 100644 source/3rd-party/Luax/luax_memberref.h create mode 100644 source/3rd-party/Luax/luax_ref.cpp create mode 100644 source/3rd-party/Luax/luax_ref.h create mode 100644 source/3rd-party/Luax/luax_reftable.cpp create mode 100644 source/3rd-party/Luax/luax_reftable.h create mode 100644 source/3rd-party/Luax/luax_runtime.cpp create mode 100644 source/3rd-party/Luax/luax_runtime.h create mode 100644 source/3rd-party/Luax/luax_state.cpp create mode 100644 source/3rd-party/Luax/luax_state.h create mode 100644 source/3rd-party/Luax/luax_state.inl (limited to 'source/3rd-party/Luax') diff --git a/source/3rd-party/Luax/luax.h b/source/3rd-party/Luax/luax.h new file mode 100644 index 0000000..d05c258 --- /dev/null +++ b/source/3rd-party/Luax/luax.h @@ -0,0 +1,14 @@ +#ifndef __LUAX_H__ +#define __LUAX_H__ + +#include "luax_state.h" +#include "luax_runtime.h" +#include "luax_ref.h" +#include "luax_reftable.h" +#include "luax_enum.h" +#include "luax_class.hpp" +#include "luax_memberref.h" +#include "luax_class.inl" +#include "luax_state.inl" + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_cfunctions.cpp b/source/3rd-party/Luax/luax_cfunctions.cpp new file mode 100644 index 0000000..d93a0ee --- /dev/null +++ b/source/3rd-party/Luax/luax_cfunctions.cpp @@ -0,0 +1,19 @@ +#include "luax_cfunctions.h" +#include "luax_config.h" + +namespace Luax +{ + + int luax_c_getupvalue(lua_State* L) + { + lua_pushvalue(L, lua_upvalueindex(1)); + return 1; + } + + int luax_c_errfunc(lua_State* L) + { + cc8* msg = luaL_optstring(L, lua_upvalueindex(1), ""); + return luaL_error(L, msg); + } + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_cfunctions.h b/source/3rd-party/Luax/luax_cfunctions.h new file mode 100644 index 0000000..2570bb9 --- /dev/null +++ b/source/3rd-party/Luax/luax_cfunctions.h @@ -0,0 +1,25 @@ +#ifndef __LUAX_CFUNCTIONS_H__ +#define __LUAX_CFUNCTIONS_H__ + +#include "luax_config.h" + +/** + * luax_cfunction里的函数用来注册给lua,一些特殊功能的通用函数。 +*/ + +namespace Luax +{ + + /// + /// 获得第一个upvalue + /// + extern int luax_c_getupvalue(lua_State* L); + + /// + /// 调用此函数时会报错,upvalue(1)是错误信息 + /// + extern int luax_c_errfunc(lua_State* L); + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_class.cpp b/source/3rd-party/Luax/luax_class.cpp new file mode 100644 index 0000000..e2019d4 --- /dev/null +++ b/source/3rd-party/Luax/luax_class.cpp @@ -0,0 +1,243 @@ +#include "luax_class.hpp" +#include "luax_runtime.h" +#include "luax_cfunctions.h" + +namespace Luax +{ + +#if LUAX_ENABLE_PLAIN_CLASS + + int LuaxPlainClass::registry(lua_State* L) + { + LUAX_STATE(L); + + // params: + // 1: class name + + cc8* type = state.GetValue(1, ""); + + lua_newtable(L); // class table + + // GetClassName() + lua_pushstring(L, type); + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClassName"); + + // GetClass() + lua_pushvalue(L, -1); // class table + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClass"); + + // TypeOf() + lua_pushcfunction(L, l_TypeOf); + lua_setfield(L, -2, "TypeOf"); + + // New() + lua_pushvalue(L, -1); // class table + lua_pushcclosure(L, l_New, 1); + lua_setfield(L, -2, "New"); + + // Extend() + lua_pushvalue(L, -1); // class table + lua_pushcclosure(L, l_Extend, 1); + lua_setfield(L, -2, "Extend"); + + lua_pushvalue(L, -1); // class table + lua_setfield(L, -2, "__index"); + + lua_pushstring(L, type); + lua_pushcclosure(L, l___tostring, 1); + lua_setfield(L, -2, "__tostring"); + + return 1; + } + + int LuaxPlainClass::l___tostring(lua_State* L) + { + // upvalues: + // 1: class name + + // params: + // 1: instance + + if (!lua_istable(L, 1)) + { + return luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE)); + } + + cc8* type = lua_tostring(L, lua_upvalueindex(1)); + + lua_pushfstring(L, "%s: %p", type, lua_topointer(L, 1)); + + return 1; + } + + /// + /// New函数接受n个参数,并尝试获取Ctor,将参数传给Ctor初始化实例。 + /// + int LuaxPlainClass::l_New(lua_State* L) + { + LUAX_STATE(L); + + // upvalues: + // 1: class table + + // params: + // n: params + int n = lua_gettop(L); + + int classTable = lua_upvalueindex(1); + + lua_newtable(L); // instance table + + // instance 的 metatable 设置为 class + lua_pushvalue(L, classTable); + lua_setmetatable(L, -2); + + // 找到构造函数,会触发metatable.__index,根据继承链向上找。 + lua_getfield(L, classTable, "Ctor"); + if (state.IsType(-1, LUA_TFUNCTION)) + { + // stack: + // -1: Ctor() + // -2: instance + // -3~-n-2: params + + lua_insert(L, -2 - n); + // stack: + // -1: instance + // -2~-n-1: params + // -n-2: Ctor() + + lua_pushvalue(L, -1); + // stack: + // -1: instance + // -2: instance + // -3~-n-2: params + // -n-3: Ctor + + lua_insert(L, -3 - n); + // stack: + // -1: instance + // -2~-n-1: params + // -n-2: Ctor() + // -n-3: instance + + lua_insert(L, -1 - n); + // stack: + // -1~-n: params + // -n-1: instance + // -n-2: Ctor() + // -n-3: instance + + lua_pcall(L, n + 1, 0, 0); + } + else + { + state.Pop(); + } + + return 1; + } + + int LuaxPlainClass::l_Extend(lua_State* L) + { + LUAX_STATE(L); + + // upvalues: + // 1: base class + + // params: + // 1: class name + + cc8* type = state.GetValue(1, ""); + + int baseClass = lua_upvalueindex(1); + + lua_newtable(L); // class table + + // GetClassName() + lua_pushstring(L, type); + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClassName"); + + // GetClass() + lua_pushvalue(L, -1); // class table + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClass"); + + // New() + lua_pushvalue(L, -1); // class table + lua_pushcclosure(L, l_New, 1); + lua_setfield(L, -2, "New"); + + // Extend() + lua_pushvalue(L, -1); // class table + lua_pushcclosure(L, l_Extend, 1); + lua_setfield(L, -2, "Extend"); + + // .__base 用来索引到基类 + lua_pushvalue(L, baseClass); // base class + lua_setfield(L, -2, "__base"); + + lua_pushvalue(L, -1); // class table + lua_setfield(L, -2, "__index"); + + lua_pushstring(L, type); + lua_pushcclosure(L, l___tostring, 1); + lua_setfield(L, -2, "__tostring"); + + // class的metatable设置为baseClass + lua_pushvalue(L, baseClass); + lua_setmetatable(L, -2); + + return 1; + } + + int LuaxPlainClass::l_TypeOf(lua_State* L) + { + // params: + // 1: lua instance + // 2: type string + + LUAX_STATE(L); + + cc8* type = state.GetValue(2, ""); + + if (!lua_istable(L, 1)) + { + return luaL_typerror(L, 1, "Object"); + } + + lua_pushvalue(L, 1); // lua instance + + while (lua_getmetatable(L, -1)) + { + lua_getfield(L, -1, "GetClassName"); + if (lua_isfunction(L, -1)) + { + state.Call(0, 1); + cc8* name = state.GetValue(-1, ""); + if (strcmp(name, type) == 0) + { + lua_pushboolean(L, true); + return 1; + } + else + { + state.Pop(); // name + } + } + else + { + state.Pop(); + } + } + + lua_pushboolean(L, false); + return 1; + } + +#endif /*LUAX_ENABLE_PLAIN_CLASS*/ + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_class.hpp b/source/3rd-party/Luax/luax_class.hpp new file mode 100644 index 0000000..ea1fab9 --- /dev/null +++ b/source/3rd-party/Luax/luax_class.hpp @@ -0,0 +1,176 @@ +#ifndef __LUAX_CLASS_H__ +#define __LUAX_CLASS_H__ + +#include + +#include "luax_config.h" +#include "luax_ref.h" +#include "luax_memberref.h" +#include "luax_cfunctions.h" + +namespace Luax +{ + +#define LUAX_DECL_METHOD(mtd) static int mtd(lua_State* L) + + /// + /// RegisterLuaxClass 注册类的方法和成员,比如枚举、常量等到class table + /// LuaxGetFactoryName 获得工厂的类名,同时用来避免注册时错误注册为了singleton,通过编译时报错避免 + /// +#define LUAX_DECL_FACTORY(type) \ + static void RegisterLuaxClass(Luax::LuaxState&);\ + static void RegisterLuaxPostprocess(Luax::LuaxState&); \ + static const char* GetLuaxFactoryName() { return #type; };\ + static const char* GetLuaxClassName() { return #type; };\ + static bool IsLuaxClassSingleton() { return false; }; + + /// + /// RegisterLuaxClass 注册类的方法和成员,比如枚举、常量等到class table + /// LuaxGetSingletonName 获得单例的类名 + /// +#define LUAX_DECL_SINGLETON(type) \ + static void RegisterLuaxClass(Luax::LuaxState&); \ + static void RegisterLuaxPostprocess(Luax::LuaxState&); \ + static const char* GetLuaxSingletonName() { return #type; }; \ + static const char* GetLuaxClassName() { return #type; }; \ + static bool IsLuaxClassSingleton() { return true; }; + +#define LUAX_IMPL_METHOD(type, f) int type::f(lua_State* L) + +#define LUAX_REGISTRY(type) void type::RegisterLuaxClass(Luax::LuaxState& state) + +#define LUAX_POSTPROCESS(type) void type::RegisterLuaxPostprocess(Luax::LuaxState& state) + +#define LUAX_REGISTER_FACTORY(stt, type) stt.RegisterFactory() + +#define LUAX_REGISTER_SINGLETON(stt, type) stt.RegisterSingleton() + + /// + /// 需要暴露给lua的native class需要继承此类。通过lua管理的实例要确保引用计数的正确性,在多个线程中需要确定不会误释放。 + /// + template + class LuaxNativeClass + { + public: + + /// + /// 将userdata作为key,在ref table里对userdata添加一个引用,以维持userdata的生命周期。 + /// + template void LuaRetain(LuaxState& state, U* userdata); + + /// + /// 对userdata减少一个引用在ref table里,以尝试回收userdata。 + /// + template void LuaRelease(LuaxState& state, U* userdata); + + protected: + + LuaxNativeClass(); + virtual ~LuaxNativeClass(); + + /// + /// 将userdata push到栈顶,如果没有初始化mUserdata,初始化设置好元表并把初始化好的userdata留在栈顶。并添加一个引用。 + /// + bool PushLuaxUserdata(LuaxState& state); + bool PushLuaxMemberTable(LuaxState& state); + bool PushLuaxRefTable(LuaxState& state); + + /// + /// 成员引用管理,在实例的ref table里。设置、取、清除 + /// + void SetMemberRef(LuaxState& state, LuaxMemberRef& memRef, int idx); + bool PushMemberRef(LuaxState& state, LuaxMemberRef& memRef); + void ClearMemberRef(LuaxState& state, LuaxMemberRef& memRef); + + private: + + friend class LuaxState; + + static void RegisterLuaxClass(LuaxState& state); + static void RegisterLuaxFactoryClass(LuaxState& state); + static void RegisterLuaxSingletonClass(LuaxState& state); + + static void SetLuaxClassTableRef(LuaxState& state, int idx); + + static void PushLuaxClassTable(LuaxState& state); + + /// + /// 屏蔽取地址运算符,如果需要地址,只能通过在堆上创建实例得到。在栈上和静态区的变量不能取地址。保证引用计数的准确。如 + /// 果需要穿引用,使用引用传递而不是传递地址。 + /// + void* operator &(); + + /// + /// 创建userdata,绑定实例到state。 + /// + void BindToLua(LuaxState& state); + + //------------------------------------------------------------------------------------------------------------ + + /// + /// 所有LuaxNativeClass类型的实例共享的内容 + /// + static LuaxStrongRef mClassTable; // class table,工厂和单例都有 + static LuaxStrongRef mSingletonRefTable; // 如果类是单例,这个用来保存singleton的成员,以保证不会被回收类似普通类的 + // ref table。单例的成员是全生命周期的,所以直接在_LUAX_STRONGREF_TABLE + + /// + /// 通过userdata可以拿到: + /// 1: ref table + /// 2: member table + /// 3: class table + /// + LuaxWeakRef mUserdata; + + public: + + //------------------------------------------------------------------------------------------------------------ + // 公共内容 + + LUAX_DECL_METHOD( l___tostring ); + LUAX_DECL_METHOD( l_GetClass ); + LUAX_DECL_METHOD( l_GetClassName ); + + //------------------------------------------------------------------------------------------------------------ + // 工厂类相关 + + LUAX_DECL_METHOD( l___gc ); +#if LUAX_ENABLE_NATIVE_EXTEND + LUAX_DECL_METHOD( l_ExtendFactory ); +#endif + LUAX_DECL_METHOD( l_GetRefTable ); + LUAX_DECL_METHOD( l_New ); + + //------------------------------------------------------------------------------------------------------------ + // 单例类相关 +#if LUAX_ENABLE_NATIVE_EXTEND + LUAX_DECL_METHOD( l_ExtendSingleton ); +#endif + }; + + //-------------------------------------------------------------------------------------------------------------- + +#if LUAX_ENABLE_PLAIN_CLASS + /// + /// 纯lua类 + /// + class LuaxPlainClass + { + public: + + /// + /// 用来注册类的入口函数。可以通过registry(类名)注册类。 + /// + static int registry(lua_State* L); + + LUAX_DECL_METHOD( l___tostring ); + LUAX_DECL_METHOD( l_Extend ); + LUAX_DECL_METHOD( l_New ); + LUAX_DECL_METHOD( l_TypeOf ); + + }; +#endif + +} + +#endif \ No newline at end of file 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 + int LuaxNativeClass::l_GetClassName(lua_State* L) + { + LUAX_SETUP(L, "*"); + + cc8* type = T::GetLuaxClassName(); + state.Push(type); + return 1; + } + + //---------------------------------------------------------------------------------------------------------------- + + /// + /// 注册工厂和单例共有的类成员 + /// + template + void LuaxNativeClass::RegisterLuaxClass(LuaxState& state) + { + luaL_Reg regTable[] = { + { "GetClass", l_GetClass }, + { "GetClassName", l_GetClassName }, + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + /// + /// 工厂类的成员,注册在class table + /// + template + void LuaxNativeClass::RegisterLuaxFactoryClass(LuaxState& state) + { + luaL_Reg regTable[] = { + { "GetRefTable", l_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() + { + } + + template + LuaxNativeClass::~LuaxNativeClass() + { + } + + template + template + void LuaxNativeClass::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(-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::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(-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 + bool LuaxNativeClass::PushLuaxUserdata(LuaxState& state) + { + assert(!T::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; + } + } + } + state.SetTop(top); + lua_pushnil(state); + return false; + } + + template + bool LuaxNativeClass::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 table,member table和class table。 + /// ref table 是kv强引用table,保存对其他userdata的引用计数(通过userdata作为key,计数为value),以及成员引用 + /// member table 保存lua创建的实例的成员 + /// class table 所有本类型的实例共有的函数表 + /// + template + void LuaxNativeClass::BindToLua(LuaxState& state) + { + // 单例不能绑定userdata + assert(!T::IsLuaxClassSingleton()); + assert(!mUserdata); + + // 创建userdata并留在栈顶 + state.PushPtrUserData(this); + + 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 + 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的弱引用,方便通过PushLuaUserdata方法返回lua对象 + mUserdata.SetRef(state, -1); + assert(mUserdata); + } + + /// + /// 成员引用管理 + /// + template + void LuaxNativeClass::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 + bool LuaxNativeClass::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 + void LuaxNativeClass::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 + int LuaxNativeClass::l___gc(lua_State* L) + { + LUAX_SETUP(L, "U"); + T* self = state.GetLuaUserdata(1); + delete self; + return 0; + } + + /// + /// 输出格式如下: + /// 地址 类名 + /// + template + int LuaxNativeClass::l___tostring(lua_State* L) + { + // params: + // 1: userdata + + LUAX_STATE(L); + T* self = state.GetLuaUserdata(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 = T::GetLuaxClassName(); + } + lua_pushfstring(L, "%s: %p", classname, self); + return 1; + } + return 0; + } + +#if LUAX_ENABLE_NATIVE_EXTEND + /// + /// 派生出子类,在lua里对派生类的成员和行为进行重新设计,但是保证了userdata的统一。Native class的派生提供Ctor支持,在 + /// native实体创建后可以使用Ctor进行初始化,派生类拥有和基类一样的New参数列表,且native对象是一样的类型。 + /// + template + int LuaxNativeClass::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 + int LuaxNativeClass::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 + int LuaxNativeClass::l_GetClass(lua_State* L) + { + LUAX_STATE(L); + if (!mClassTable) + lua_pushnil(L); + else + mClassTable.PushRef(state); + return 1; + } + + template + int LuaxNativeClass::l_GetRefTable(lua_State* L) + { + LUAX_STATE(L); + T* self = state.GetLuaUserdata(1); + bool success = self->PushLuaxRefTable(state); + if (!success) + lua_pushnil(L); + return 1; + } + + template + int LuaxNativeClass::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 LuaxStrongRef LuaxNativeClass::mClassTable; // class table + template LuaxStrongRef LuaxNativeClass::mSingletonRefTable; // 单例 + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_config.h b/source/3rd-party/Luax/luax_config.h new file mode 100644 index 0000000..c6562cc --- /dev/null +++ b/source/3rd-party/Luax/luax_config.h @@ -0,0 +1,60 @@ +#ifndef __LUAX_TYPE_H__ +#define __LUAX_TYPE_H__ + +#include + +extern "C" { +#include "lua51/lua.h" +#include "lua51/lualib.h" +#include "lua51/lauxlib.h" +} + +#include + +namespace Luax +{ + + typedef unsigned int uint; + typedef unsigned long uintptr; + typedef long sintptr; + + typedef const char cc8; + + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + typedef unsigned long long u64; + + typedef signed char s8; + typedef signed short s16; + typedef signed int s32; + typedef signed long long s64; + +#ifdef _WIN32 + #define LUAX_FINAL final + #define LUAX_LIBRARY_EXPORT __declspec(dllexport) + #define LUAX_LIBRARY_IMPORT __declspec(dllimport) + #define LUAX_FORCE_INLINE __forceinline + #define LUAX_RESTRICT __restrict + #define LUAX_ATTRIBUTE_USED + #define LUAX_ABSTRACT + #define LUAX_API LUAX_LIBRARY_EXPORT +#else + #define LUAX_FINAL final + #define LUAX_LIBRARY_EXPORT __attribute__((visibility("default"))) + #define LUAX_LIBRARY_IMPORT + #define LUAX_FORCE_INLINE __attribute__((always_inline)) inline + #define LUAX_RESTRICT __restrict__ + #define LUAX_ATTRIBUTE_USED __attribute__((used)) + #define LUAX_ABSTRACT + #define LUAX_API LUAX_LIBRARY_EXPORT +#endif + +#define LUAX_ENABLE_NATIVE_EXTEND 0 + +#define LUAX_ENABLE_PLAIN_CLASS 1 +#define LUAX_ENABLE_PLAIN_ENABLE 1 + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_context.cpp b/source/3rd-party/Luax/luax_context.cpp new file mode 100644 index 0000000..d41c24f --- /dev/null +++ b/source/3rd-party/Luax/luax_context.cpp @@ -0,0 +1,29 @@ +#include "luax_context.h" + +namespace Luax +{ + + LuaxContext::LuaxContext(lua_State* L) + : state(L) + { + assert(state); + } + + LuaxContext::~LuaxContext() + { + } + + // 初始化context + void LuaxContext::Setup() + { + SetupRefTables(); + } + + void LuaxContext::SetupRefTables() + { + // strong ref和 weak ref + strongRefTable.Init(state, "_LUAX_STRONGREF_TABLE"); + weakRefTable.Init(state, "_LUAX_WEAKREF_TABLE", "v"); + } + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_context.h b/source/3rd-party/Luax/luax_context.h new file mode 100644 index 0000000..01c5937 --- /dev/null +++ b/source/3rd-party/Luax/luax_context.h @@ -0,0 +1,36 @@ +#ifndef __LUAX_CONTEXT_H__ +#define __LUAX_CONTEXT_H__ + +#include "luax_ref.h" +#include "luax_config.h" +#include "luax_state.h" + +namespace Luax +{ + + /// + /// 单个lua_state相关的context。是一系列代理的集合,拷贝也没关系,主要是为了节约内存。 + /// + class LuaxContext + { + public: + LuaxContext(lua_State* L); + ~LuaxContext(); + + void Setup(); + + LuaxState state; // lua state + LuaxRefTable strongRefTable; // strong ref table + LuaxRefTable weakRefTable; // weak ref table + + size_t objectCount; // 统计所有在此state中创建的实例 + + private: + + void SetupRefTables(); + + }; + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_enum.cpp b/source/3rd-party/Luax/luax_enum.cpp new file mode 100644 index 0000000..88bbab4 --- /dev/null +++ b/source/3rd-party/Luax/luax_enum.cpp @@ -0,0 +1,67 @@ +#include "luax_enum.h" +#include "luax_state.h" +#include "luax_runtime.h" + +namespace Luax +{ + + /// + /// 只读metatable的__index + /// + int l_rmt__index(lua_State* L) + { + // params: + // 1: enum table + // 2: key + + // upvalues: + // 1: metatable + + int mt = lua_upvalueindex(1); + lua_pushvalue(L, 2); + lua_rawget(L, mt); + + return 1; + } + + int l_rmt__newindex(lua_State* L) + { + // upvalue: + // 1: enum table name + + cc8* name = lua_tostring(L, lua_upvalueindex(1)); + + return luaL_error(L, "Enum called \"%s\" is readonly.", name); + } + + //-------------------------------------------------------------------------------------------------------------- +#if LUAX_ENABLE_PLAIN_ENABLE + int LuaxPlainEnum::registry(lua_State* L) + { + // params: + // 1: enum name + // 2: metatable + + cc8* name = luaL_checkstring(L, 1); + + if (!lua_istable(L, 2)) + { + return luaL_error(L, "Create plain enum failed. Require table, but get %s", luaL_typename(L, 2)); + } + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + lua_pushstring(L, name); + lua_pushcclosure(L, l_rmt__newindex, 1); + lua_setfield(L, -2, "__newindex"); + + lua_newtable(L); // enum table + + lua_pushvalue(L, -2); // metatable + lua_setmetatable(L, -2); + + return 1; + } +#endif +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_enum.h b/source/3rd-party/Luax/luax_enum.h new file mode 100644 index 0000000..36f6bab --- /dev/null +++ b/source/3rd-party/Luax/luax_enum.h @@ -0,0 +1,38 @@ +#ifndef __LUAX_ENUM_H__ +#define __LUAX_ENUM_H__ + +#include "luax_config.h" + +namespace Luax +{ + + /// + /// 导出枚举,枚举是一类不可修改整型集合,枚举的值在 + /// + struct LuaxEnum + { + cc8* name; + int value; + }; + + extern int l_rmt__index(lua_State* L); + + extern int l_rmt__newindex(lua_State* L); + + //-------------------------------------------------------------------------------------------------------------- +#if LUAX_ENABLE_PLAIN_ENABLE + /// + /// 纯lua的枚举,创建不可修改的table + /// + class LuaxPlainEnum + { + public: + + static int registry(lua_State* L); + + }; +#endif + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_memberref.cpp b/source/3rd-party/Luax/luax_memberref.cpp new file mode 100644 index 0000000..a8a09ba --- /dev/null +++ b/source/3rd-party/Luax/luax_memberref.cpp @@ -0,0 +1,16 @@ +#include "luax_memberref.h" + +namespace Luax +{ + + LuaxMemberRef::LuaxMemberRef() + : refID(LUA_NOREF) + { + } + + LuaxMemberRef::~LuaxMemberRef() + { + + } + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_memberref.h b/source/3rd-party/Luax/luax_memberref.h new file mode 100644 index 0000000..cda7946 --- /dev/null +++ b/source/3rd-party/Luax/luax_memberref.h @@ -0,0 +1,27 @@ +#ifndef __LUAX_MEMBER_REF_H__ +#define __LUAX_MEMBER_REF_H__ + +#include "luax_config.h" + +namespace Luax +{ + + /// + /// 实例的ref table保存的member ref。由luax class做具体的管理。实例的ref table是强引用,用来管理里面member的生命周期。 + /// 用来在lua和native之间进行数据沟通。 + /// + class LuaxMemberRef + { + public: + LuaxMemberRef(); + ~LuaxMemberRef(); + + inline operator bool() { return refID != LUA_NOREF; }; + + int refID; + + }; + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_ref.cpp b/source/3rd-party/Luax/luax_ref.cpp new file mode 100644 index 0000000..544861d --- /dev/null +++ b/source/3rd-party/Luax/luax_ref.cpp @@ -0,0 +1,69 @@ +#include "luax_runtime.h" +#include "luax_ref.h" + +namespace Luax +{ + + LuaxRef::LuaxRef(int mode) + : mRefID(LUA_NOREF) + , mMode(mode) + { + } + + LuaxRef::~LuaxRef() + { + } + + LuaxRef::operator bool() + { + return (mRefID != LUA_NOREF); + } + + bool LuaxRef::PushRef(LuaxState& state) + { + assert(mRefID != LUA_NOREF); + + LuaxRuntime& runtime = LuaxRuntime::Get(); + + if (mMode == STRONG_REF) + { + LuaxRefTable& table = runtime[state.GetHandle()].strongRefTable; + table.PushRef(state, mRefID); + } + else if (mMode == WEAK_REF) + { + LuaxRefTable& table = runtime[state.GetHandle()].weakRefTable; + table.PushRef(state, mRefID); + } + else + { + return false; + } + } + + void LuaxRef::SetRef(LuaxState& state, int idx) + { + LuaxRuntime& runtime = LuaxRuntime::Get(); + if (mMode == STRONG_REF) + { + LuaxRefTable& table = runtime[state.GetHandle()].strongRefTable; + mRefID = table.Ref(state, idx); + } + else if (mMode == WEAK_REF) + { + LuaxRefTable& table = runtime[state.GetHandle()].weakRefTable; + mRefID = table.Ref(state, idx); + } + } + + LuaxStrongRef::LuaxStrongRef() + : LuaxRef(STRONG_REF) + { + } + + LuaxWeakRef::LuaxWeakRef() + : LuaxRef(WEAK_REF) + { + } + +} diff --git a/source/3rd-party/Luax/luax_ref.h b/source/3rd-party/Luax/luax_ref.h new file mode 100644 index 0000000..b7aabe5 --- /dev/null +++ b/source/3rd-party/Luax/luax_ref.h @@ -0,0 +1,62 @@ +#ifndef __LUAX_REF_H__ +#define __LUAX_REF_H__ + +#include "luax_config.h" +#include "luax_state.h" + +namespace Luax +{ + + /// + /// 引用,存在LUA_REGISTRYINDEX下面的两个表里 + /// + class LuaxRef + { + public: + + enum + { + STRONG_REF, + WEAK_REF + }; + + LuaxRef(int mode = STRONG_REF); + virtual ~LuaxRef(); + + operator bool(); + + void SetRef(LuaxState& state, int idx); + bool PushRef(LuaxState& state); + + int GetRefID(); + + private: + + int mRefID; // luaL_ref + int mMode; // strong or weak + + }; + + /// + /// 强引用,在LUA_REGISTRYINDEX["_LUAX_STRONGREF_TABLE"]里,保证lua object不会被回收。 + /// + class LuaxStrongRef: public LuaxRef + { + public: + LuaxStrongRef(); + + }; + + /// + /// 弱引用,在LUA_REGISTRYINDEX["_LUAX_WEAKREF_TABLE"]里,不影响lua object的回收,只是作为一个方便取lua object的映射。 + /// + class LuaxWeakRef : public LuaxRef + { + public: + LuaxWeakRef(); + + }; + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_reftable.cpp b/source/3rd-party/Luax/luax_reftable.cpp new file mode 100644 index 0000000..602c9eb --- /dev/null +++ b/source/3rd-party/Luax/luax_reftable.cpp @@ -0,0 +1,120 @@ +#include "luax_reftable.h" +#include "luax_state.h" + +namespace Luax +{ + + LuaxRefTable::LuaxRefTable() + : mState(nullptr) + { + } + + LuaxRefTable::~LuaxRefTable() + { + } + + void LuaxRefTable::Init(LuaxState& state, cc8* name, cc8* mode) + { + assert(!mState); + assert(name); + + mName = name; + mMode = 0; + for (int i = 0; mode && mode[i]; ++i) + { + if (mode[i] == 'k') mMode |= WEAK_KEY; + else if (mode[i] == 'v') mMode |= WEAK_VALUE; + } + mState = state.GetHandle(); + + state.GetField(LUA_REGISTRYINDEX, name); // register[mName] + if (state.IsNil(-1)) + { + state.Pop(); + + lua_newtable(state); // ref table + int ridx = state.AbsIndex(-1); + lua_newtable(state); // metatable of ref table + int idx = state.AbsIndex(-1); + + // __mode + if (mode) + { + state.Push(mode); + state.SetField(idx, "__mode"); + } + + state.Settop(idx); + lua_setmetatable(state, ridx); + + state.Settop(ridx); + state.SetField(LUA_REGISTRYINDEX, name); + } + else + { + state.Pop(); + } + } + + bool LuaxRefTable::IsKeyWeak() + { + assert(mState); + + return mMode & WEAK_KEY; + } + + bool LuaxRefTable::IsValueWeak() + { + assert(mState); + + return mMode & WEAK_VALUE; + } + + int LuaxRefTable::Ref(LuaxState& state, int idx) + { + assert(mState && mState == state.GetHandle()); + + idx = state.AbsIndex(idx); + state.GetField(LUA_REGISTRYINDEX, mName); // ref table + lua_pushvalue(state, idx); // stuff + int refID = luaL_ref(state, -2); + assert(refID != LUA_NOREF); + state.Pop(); + return refID; + } + + void LuaxRefTable::Unref(LuaxState& state, int refID) + { + assert(mState && mState == state.GetHandle()); + + state.GetField(LUA_REGISTRYINDEX, mName); // ref table + luaL_unref(state, -1, refID); + state.Pop(); + return; + } + + void LuaxRefTable::PushRefTable(LuaxState& state) + { + assert(mState && mState == state.GetHandle()); + + lua_getfield(state, LUA_REGISTRYINDEX, mName); + } + + void LuaxRefTable::PushRef(LuaxState& state, int refID) + { + assert(mState && mState == state.GetHandle()); + + lua_getfield(state, LUA_REGISTRYINDEX, mName); + lua_rawgeti(state, -1, refID); + lua_replace(state, -2); + } + + void LuaxRefTable::Clear(LuaxState& state) + { + assert(mState && mState == state.GetHandle()); + + lua_newtable(state); + state.SetField(LUA_REGISTRYINDEX, mName); + } + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_reftable.h b/source/3rd-party/Luax/luax_reftable.h new file mode 100644 index 0000000..58e4b9c --- /dev/null +++ b/source/3rd-party/Luax/luax_reftable.h @@ -0,0 +1,67 @@ +#ifndef __LUAX_REFTABLE_H__ +#define __LUAX_REFTABLE_H__ + +#include "luax_config.h" + +namespace Luax +{ + + class LuaxState; + + /// + /// ref table 管理,对strong ref table和weak ref table两个table的代理。 + /// + class LuaxRefTable + { + public: + + enum + { + WEAK_KEY = 1, + WEAK_VALUE = 1 << 1 + }; + + LuaxRefTable(); + ~LuaxRefTable(); + + inline operator bool() { return mState; }; + + void Init(LuaxState& state, cc8* name, cc8* mode = nullptr); + + bool IsKeyWeak(); + bool IsValueWeak(); + + /// + /// 对stack[idx]的实体在此ref table中增加一个引用,并返回refID + /// + int Ref(LuaxState& state, int idx); + void Unref(LuaxState& state, int refID); + + /// + /// 将此 ref table 放在栈顶 + /// + void PushRefTable(LuaxState& state); + + /// + /// 将 reftable[refID] 放在栈顶 + /// + void PushRef(LuaxState& state, int refID); + + /// + /// 清空 ref table,表还留在LUA_REGISTRYINDEX[mName] + /// + void Clear(LuaxState& state); + + private: + + friend class LuaxState; + + lua_State* mState; // 用来做一些确认工作 + cc8* mName; // ref table的名称 + int mMode; // ref table的类型 + + }; + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_runtime.cpp b/source/3rd-party/Luax/luax_runtime.cpp new file mode 100644 index 0000000..b45d36a --- /dev/null +++ b/source/3rd-party/Luax/luax_runtime.cpp @@ -0,0 +1,89 @@ +#ifndef __LUAX_RUNTIME_H_ +#define __LUAX_RUNTIME_H_ + +#include "luax_runtime.h" + +using namespace std; + +namespace Luax +{ + + LuaxRuntime* LuaxRuntime::mRuntime = nullptr; + + LuaxRuntime::LuaxRuntime() {}; + LuaxRuntime::~LuaxRuntime() {}; + + LuaxRuntime& LuaxRuntime::Get() + { + if (mRuntime == nullptr) + mRuntime = new LuaxRuntime(); + + return *mRuntime; + } + + lua_State* LuaxRuntime::Open() + { + lua_State* L = lua_open(); + assert(L); + + // 1) 加入 + mContexts.insert(pair(L, LuaxContext(L))); + // 2) 初始化context + (*this)[L].Setup(); + + return L; + } + + void LuaxRuntime::Close(lua_State* L) + { + map::iterator it = mContexts.find(L); + if (it != mContexts.end()) + { + lua_close(it->second.state); + mContexts.erase(it); + } + } + + bool LuaxRuntime::HasLuaxState(lua_State* L) + { + map::iterator it = mContexts.find(L); + return it != mContexts.end(); + } + + LuaxState& LuaxRuntime::GetLuaxState(lua_State* L) + { + map::iterator it = mContexts.find(L); + if (it != mContexts.end()) + { + return it->second.state; + } + } + + LuaxRefTable& LuaxRuntime::GetStrongRefTable(lua_State* L) + { + map::iterator it = mContexts.find(L); + if (it != mContexts.end()) + { + return it->second.strongRefTable; + } + } + + LuaxRefTable& LuaxRuntime::GetWeaksRefTable(lua_State* L) + { + map::iterator it = mContexts.find(L); + if (it != mContexts.end()) + { + return it->second.weakRefTable; + } + } + + LuaxContext& LuaxRuntime::operator[](lua_State* L) + { + map::iterator it = mContexts.find(L); + assert(it != mContexts.end()); + return it->second; + } + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_runtime.h b/source/3rd-party/Luax/luax_runtime.h new file mode 100644 index 0000000..1234627 --- /dev/null +++ b/source/3rd-party/Luax/luax_runtime.h @@ -0,0 +1,59 @@ +#ifndef __LUAX_RUNTIME_H__ +#define __LUAX_RUNTIME_H__ + +#include + +#include "luax_ref.h" +#include "luax_config.h" +#include "luax_state.h" +#include "luax_context.h" + +namespace Luax +{ + + /// + /// 统一管理程序所有的lua states。 + /// + class LuaxRuntime + { + public: + + static LuaxRuntime& Get(); + + /// + /// 创建一个新的lua_State并保存下来。返回的lua_State*是一个8\4字节的key。 + /// + lua_State* Open(); + + /// + /// 关闭lua_State并将其从runtime中删除。 + /// + void Close(lua_State* L); + + bool HasLuaxState(lua_State* L); + LuaxState& GetLuaxState(lua_State* L); + LuaxRefTable& GetStrongRefTable(lua_State* L); + LuaxRefTable& GetWeaksRefTable(lua_State* L); + + LuaxContext& operator[](lua_State* L); + + private: + + LuaxRuntime(); + ~LuaxRuntime(); + + static LuaxRuntime* mRuntime; + + /// + /// 从lua_State handle到context的映射 + /// + std::map mContexts; + + }; + +#define LUAX_RUNTIME() \ + LuaxRuntime& runtime = LuaxRuntime::Get() + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_state.cpp b/source/3rd-party/Luax/luax_state.cpp new file mode 100644 index 0000000..881aaea --- /dev/null +++ b/source/3rd-party/Luax/luax_state.cpp @@ -0,0 +1,737 @@ +//#include "luax_class.h" +#include "luax_enum.h" +#include "luax_state.h" +#include "luax_runtime.h" +#include "luax_class.hpp" + +namespace Luax +{ + + LuaxState::LuaxState(lua_State* state) + : mState(state) + { + assert(state); + } + + LuaxState::LuaxState(const LuaxState& state) + : mState(state.mState) + { + assert(state.mState); + } + + LuaxState::~LuaxState() + { + } + + void LuaxState::OpenLibs() + { + luaL_openlibs(mState); + } + + void LuaxState::PushGlobalNamespace() + { + int top = GetTop(); + + lua_newtable(mState); // pseudo namespace table + int pnt = GetTop(); + + lua_newtable(mState); // metatable + int mt = GetTop(); + + // __index = _G + // __newindex = _G + lua_pushvalue(mState, LUA_GLOBALSINDEX); + lua_pushvalue(mState, LUA_GLOBALSINDEX); + lua_setfield(mState, mt, "__index"); + lua_setfield(mState, mt, "__newindex"); + + lua_setmetatable(mState, pnt); + + // stack: + // -1 pseudo global namespace + } + + void LuaxState::PushNamespace(cc8* name) + { + assert(IsNamespace(-1)); + + int top = GetTop(); + + lua_getfield(mState, -1, name); + if (lua_isnil(mState, -1)) + { + lua_pop(mState, 1); + + lua_newtable(mState); + lua_pushvalue(mState, -1); + lua_setfield(mState, top, name); + } + + // stack: + // -1 namespace + } + + void LuaxState::PopNamespace() + { + assert(lua_istable(mState, -1)); + lua_pop(mState, 1); + } + + bool LuaxState::IsNamespace(int idx) + { + return lua_istable(mState, idx); + } + + void LuaxState::DoString(const std::string& code) + { + luaL_dostring(mState, code.c_str()); + } + + int LuaxState::AbsIndex(int idx) + { +/* +#define abs_index(mState, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ + lua_gettop(mState) + (i) + 1) +*/ + if (idx < 0) { + //return lua_gettop(mState) + idx + 1; + return ((idx) > 0 || (idx) <= LUA_REGISTRYINDEX ? (idx) : \ + lua_gettop(mState) + (idx)+1); + } + return idx; + } + + void LuaxState::Call(int nArgs, int nResults) + { + lua_pcall(mState, nArgs, nResults, 0); + } + + void LuaxState::PushNil() + { + lua_pushnil(mState); + } + + void LuaxState::Push(bool value) + { + lua_pushboolean(mState, value ? 1 : 0); + } + + void LuaxState::Push(cc8* value) + { + lua_pushstring(mState, value); + } + + void LuaxState::Push(double value) + { + lua_pushnumber(mState, value); + } + + void LuaxState::Push(float value) + { + lua_pushnumber(mState, value); + } + + void LuaxState::Push(int value) + { + lua_pushnumber(mState, value); + } + + void LuaxState::Push(u16 value) + { + lua_pushnumber(mState, value); + } + + void LuaxState::Push(u32 value) + { + lua_pushnumber(mState, value); + } + + void LuaxState::Push(u64 value) + { + lua_pushnumber(mState, (double)value); + } + + void LuaxState::Push(uintptr value) + { + lua_pushlightuserdata(mState, (void*)value); + } + + void LuaxState::Push(lua_CFunction value) + { + lua_pushcfunction(mState, value); + } + + void LuaxState::Push(void* data, size_t size) + { + lua_pushlstring(mState, (cc8*)data, size); + } + + void LuaxState::Push(const void* value) + { + lua_pushlightuserdata(mState, (void*)value); + } + + void LuaxState::PushValues(int idx, int n) + { + idx = AbsIndex(idx); + for (int i = idx; i < idx + n; ++i) + lua_pushvalue(mState, i); + } + + void LuaxState::Pop(int n /* = 1 */) + { + lua_pop(mState, n); + } + + bool LuaxState::IsNil(int idx) + { + return lua_isnil(mState, idx); + } + + bool LuaxState::IsNilOrNone(int idx) + { + int t = lua_type(mState, idx); + return ((t == LUA_TNONE) || (t == LUA_TNIL)); + } + + bool LuaxState::IsTableOrUserdata(int idx) + { + int check = lua_type(mState, idx); + return ((check == LUA_TTABLE) || (check == LUA_TUSERDATA)); + } + + bool LuaxState::IsTrueOrNotNil(int idx) + { + if (lua_isboolean(mState, idx)) { + return lua_toboolean(mState, idx) ? true : false; + } + return !lua_isnil(mState, idx); + } + + bool LuaxState::IsType(int idx, int type) + { + return (lua_type(mState, idx) == type); + } + + bool LuaxState::IsType(int idx, cc8* name, int type) + { + return this->HasField(idx, name, type); + } + + bool LuaxState::IsValid() + { + return (mState != 0); + } + + void LuaxState::Settop(int idx) + { + lua_settop(mState, idx); + } + + int LuaxState::GetTop() + { + return lua_gettop(mState); + } + + bool LuaxState::HasField(int idx, cc8* name) { + + lua_getfield(mState, idx, name); + bool hasField = (lua_isnil(mState, -1) == false); + lua_pop(mState, 1); + + return hasField; + } + + bool LuaxState::HasField(int idx, int key) { + + this->GetField(idx, key); + bool hasField = (lua_isnil(mState, -1) == false); + lua_pop(mState, 1); + + return hasField; + } + + bool LuaxState::HasField(int idx, cc8* name, int type) { + + lua_getfield(mState, idx, name); + bool hasField = (lua_type(mState, -1) == type); + lua_pop(mState, 1); + + return hasField; + } + + bool LuaxState::HasField(int idx, int key, int type) { + + this->GetField(idx, key); + bool hasField = (lua_type(mState, -1) == type); + lua_pop(mState, 1); + + return hasField; + } + + bool LuaxState::HasKeys(int idx) { + + idx = this->AbsIndex(idx); + + lua_pushnil(mState); /* first key */ + if (lua_next(mState, idx) != 0) { + lua_pop(mState, 2); + return true; + } + return false; + } + + void LuaxState::GetField(int idx, cc8* name) + { + lua_getfield(mState, idx, name); + } + + void LuaxState::GetField(int idx, int key) + { + idx = this->AbsIndex(idx); + + lua_pushinteger(mState, key); + lua_gettable(mState, idx); + } + + std::string LuaxState::GetField(int idx, cc8* key, cc8* value) + { + std::string str; + if (this->GetFieldWithType(idx, key, LUA_TSTRING)) { + str = lua_tostring(mState, -1); + lua_pop(mState, 1); + } + else { + str = value; + } + return str; + } + + std::string LuaxState::GetField(int idx, int key, cc8* value) + { + std::string str; + if (this->GetFieldWithType(idx, key, LUA_TSTRING)) { + str = lua_tostring(mState, -1); + lua_pop(mState, 1); + } + else { + str = value; + } + return str; + } + + std::string LuaxState::GetField(int idx, cc8* key, const std::string& value) + { + std::string str; + if (this->GetFieldWithType(idx, key, LUA_TSTRING)) { + str = lua_tostring(mState, -1); + lua_pop(mState, 1); + } + else { + str = value; + } + return str; + } + + std::string LuaxState::GetField(int idx, int key, const std::string& value) + { + std::string str; + if (this->GetFieldWithType(idx, key, LUA_TSTRING)) { + str = lua_tostring(mState, -1); + lua_pop(mState, 1); + } + else { + str = value; + } + return str; + } + + bool LuaxState::GetFieldWithType(int idx, cc8* name, int type) + { + lua_getfield(mState, idx, name); + if (lua_type(mState, -1) != type) { + lua_pop(mState, 1); + return false; + } + return true; + } + + bool LuaxState::GetFieldWithType(int idx, int key, int type) + { + this->GetField(idx, key); + if (lua_type(mState, -1) != type) { + lua_pop(mState, 1); + return false; + } + return true; + } + + void LuaxState::SetField(int idx, cc8* key) + { + if (IsTableOrUserdata(idx)) + { + idx = AbsIndex(idx); + lua_setfield(mState, idx, key); + } + } + + cc8* LuaxState::GetLuaTypeName(int type) + { + switch (type) { + case LUA_TNONE: return "none"; + case LUA_TNIL: return "nil"; + case LUA_TBOOLEAN: return "boolean"; + case LUA_TLIGHTUSERDATA: return "lightuserdata"; + case LUA_TNUMBER: return "number"; + case LUA_TSTRING: return "string"; + case LUA_TTABLE: return "table"; + case LUA_TFUNCTION: return "function"; + case LUA_TUSERDATA: return "userdata"; + case LUA_TTHREAD: return "thread"; + } + return "unknown"; + } + + + bool LuaxState::GetSubfieldWithType(int idx, cc8* format, int type, ...) + { + va_list args; + va_start(args, type); + + idx = this->AbsIndex(idx); + lua_pushvalue(this->mState, idx); + + for (cc8* c = format; *c; ++c) { + switch (*c) { + // number + case 'N': + lua_pushnumber(this->mState, va_arg(args, int)); + lua_gettable(this->mState, -1); + break; + + // string + case 'S': + lua_getfield(this->mState, -1, va_arg(args, char*)); + break; + + default: + lua_pushnil(this->mState); + } + + if (lua_isnil(this->mState, -1)) break; + lua_replace(this->mState, -2); + } + va_end(args); + if (lua_type(this->mState, -1) != type) { + lua_pop(this->mState, 1); + return false; + } + return true; + } + + bool LuaxState::CheckParams(int idx, cc8* format) + { + idx = AbsIndex(idx); + + for (int i = 0; format[i]; ++i) { + + int pos = idx + i; + int type = LUA_TNIL; + int expected = LUA_TNONE; + + if (pos <= GetTop()) { + type = lua_type(mState, pos); + } + + switch (format[i]) { + + // boolean + case 'B': + if (type != LUA_TBOOLEAN) expected = LUA_TBOOLEAN; + break; + + // coroutine + case 'C': + if (type != LUA_TTHREAD) expected = LUA_TTHREAD; + break; + + // function + case 'F': + if (type != LUA_TFUNCTION) expected = LUA_TFUNCTION; + break; + + // light userdata + case 'L': + if (type != LUA_TLIGHTUSERDATA) expected = LUA_TLIGHTUSERDATA; + break; + + // number + case 'N': + if (type != LUA_TNUMBER) expected = LUA_TNUMBER; + break; + + // string + case 'S': + if (type != LUA_TSTRING) expected = LUA_TSTRING; + break; + + // table + case 'T': + if (type != LUA_TTABLE) expected = LUA_TTABLE; + break; + + // userdata + case 'U': + if (type != LUA_TUSERDATA) expected = LUA_TUSERDATA; + break; + + // any type + case '*': + case '.': + break; + } + + if (expected != LUA_TNONE) { + return false; + } + } + + return true; + } + + template <> + bool LuaxState::GetValue < bool >(int idx, const bool value) { + + if (this->IsType(idx, LUA_TBOOLEAN)) { + return (lua_toboolean(this->mState, idx) != 0); + } + return value; + } + + + template <> + cc8* LuaxState::GetValue < cc8* >(int idx, const cc8* value) { + + if (this->IsType(idx, LUA_TSTRING)) { + return lua_tostring(this->mState, idx); + } + return value; + } + + template <> + std::string LuaxState::GetValue(int idx, const std::string value) + { + std::string str; + if (lua_type(this->mState, idx) == LUA_TSTRING) { + str = lua_tostring(this->mState, idx); + } + else { + str = value; + } + return str; + } + + template <> + double LuaxState::GetValue < double >(int idx, const double value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + float LuaxState::GetValue < float >(int idx, const float value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (float)lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + s8 LuaxState::GetValue < s8 >(int idx, const s8 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (s8)lua_tonumber(this->mState, idx); + } + return value; + } + + + template <> + s16 LuaxState::GetValue < s16 >(int idx, const s16 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (s16)lua_tonumber(this->mState, idx); + } + return value; + } + + + template <> + s32 LuaxState::GetValue < s32 >(int idx, const s32 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (s32)lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + s64 LuaxState::GetValue < s64 >(int idx, const s64 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (s64)lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + u8 LuaxState::GetValue < u8 >(int idx, const u8 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (u8)lua_tonumber(this->mState, idx); + } + return value; + } + + template<> + int LuaxState::GetValue(int idx, int value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (int)lua_tointeger(this->mState, idx); + } + return value; + } + + template <> + u16 LuaxState::GetValue < u16 >(int idx, const u16 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (u16)lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + u32 LuaxState::GetValue < u32 >(int idx, const u32 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (u32)lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + u64 LuaxState::GetValue < u64 >(int idx, const u64 value) + { + if (this->IsType(idx, LUA_TNUMBER)) { + return (u64)lua_tonumber(this->mState, idx); + } + return value; + } + + template <> + const void* LuaxState::GetValue < const void* >(int idx, const void* value) + { + if (this->IsType(idx, LUA_TLIGHTUSERDATA)) { + return (void*)lua_touserdata(this->mState, idx); + } + return value; + } + + void LuaxState::PushPtrUserData(void* ptr) { + + void** handle = (void**)lua_newuserdata(this->mState, sizeof(void*)); + assert(handle); + (*handle) = ptr; + } + + void LuaxState::RegisterEnum(cc8* name, LuaxEnum* en) + { + assert(name); + assert(en); + + // short name + lua_State* L = mState; + + int top = GetTop(); + + lua_newtable(L); // enum table + + int et = GetTop(); + + lua_newtable(L); // matatable + + // 所有枚举都存在metatable下,修改时触发__newindex报错 + for (; en->name; ++en) + { + lua_pushinteger(L, en->value); + lua_setfield(L, -2, en->name); + } + + // __index + //lua_pushvalue(L, -1); // metatable + //lua_pushcclosure(L, l_rmt__index, 1); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + // __newinedx + lua_pushstring(L, name); // enum name + lua_pushcclosure(L, l_rmt__newindex, 1); + lua_setfield(L, -2, "__newindex"); + + lua_setmetatable(L, et); + + lua_setfield(L, top, name); + } + + + void LuaxState::RegisterMethods(const luaL_Reg *l) + { + assert(lua_istable(mState, -1)); + // luaL_register第二个参数为空,则向-1位置注册luaL_Reg中这些函数 + luaL_register(mState, 0, l); + } + + void LuaxState::RegisterMethod(cc8* fname, lua_CFunction func) + { + assert(lua_istable(mState, -1)); + lua_pushcfunction(mState, func); + lua_setfield(mState, -1, fname); + } + + void LuaxState::RegisterPreloader(cc8* libname, lua_CFunction preloader) + { + lua_getglobal(mState, "package"); + lua_getfield(mState, -1, "preload"); + lua_pushcfunction(mState, preloader); + lua_setfield(mState, -2, libname); + lua_pop(mState, 2); + } + + void LuaxState::RegisterLib(cc8* libname, const luaL_Reg* l) + { + luaL_register(mState, libname, l); + } + +#if LUAX_ENABLE_PLAIN_CLASS + void LuaxState::RegisterPlainClassRegistry(cc8* name) + { + assert(lua_istable(mState, -1)); + lua_pushcfunction(mState, LuaxPlainClass::registry); + lua_setfield(mState, -2, name); + } +#endif + +#if LUAX_ENABLE_PLAIN_ENABLE + void LuaxState::RegisterPlainEnumRegistry(cc8* name) + { + assert(lua_istable(mState, -1)); + lua_pushcfunction(mState, LuaxPlainEnum::registry); + lua_setfield(mState, -2, name); + } +#endif + +} \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_state.h b/source/3rd-party/Luax/luax_state.h new file mode 100644 index 0000000..fbe424b --- /dev/null +++ b/source/3rd-party/Luax/luax_state.h @@ -0,0 +1,238 @@ +#ifndef __LUAX_STATE_H__ +#define __LUAX_STATE_H__ + +#include + +#include "luax_config.h" +#include "luax_reftable.h" + +namespace Luax +{ + + class LuaxContext; + class LuaxEnum; + class LuaxStrongRef; + class LuaxWeakRef; + + /// + /// 对lua_State的代理,除了保存一个lua_State的引用不保存其他内容。一个实例的metatable如下: + /// class table + /// member table + /// ref table + /// userdata + /// 从userdata通过getmetatable获取上级metatable。除此之外还有一个class table注册在对应的名称空间里。 + /// + LUAX_API class LuaxState + { + public: + + inline lua_State* operator ->() { return mState; }; + inline lua_State& operator *() { return *mState; }; + inline operator lua_State*() { return mState; } + inline operator bool() { return mState != nullptr; }; + + /// + /// 获取绑定的lua_State + /// + inline lua_State* GetHandle() { return mState; }; + + //------------------------------------------------------------------------------------------------------------ + + void OpenLibs(); + + //------------------------------------------------------------------------------------------------------------ + // 名称空间管理,名称空间就是一个表,_G是最上面的表 + + void PushGlobalNamespace(); + void PushNamespace(cc8* name); + void PopNamespace(); + bool IsNamespace(int idx); + + //------------------------------------------------------------------------------------------------------------ + + void SetTop(int top); + int GetTop(); + bool CheckParams(int idx, cc8* format); + int AbsIndex(int idx); + void Call(int nArgs, int nResults); + + //------------------------------------------------------------------------------------------------------------ + + void GetField(int idx, cc8* name); + void GetField(int idx, int key); + std::string GetField(int idx, cc8* key, cc8* value); + std::string GetField(int idx, int key, cc8* value); + std::string GetField(int idx, cc8* key, const std::string& value); + std::string GetField(int idx, int key, const std::string& value); + bool GetFieldWithType(int idx, cc8* name, int type); + bool GetFieldWithType(int idx, int key, int type); + bool GetSubfieldWithType(int idx, cc8* format, int type, ...); + static cc8* GetLuaTypeName(int type); + + void SetField(int idx, cc8* key); + + bool IsNil(int idx); + bool IsNilOrNone(int idx); + bool IsTableOrUserdata(int idx); + bool IsTrueOrNotNil(int idx); + bool IsType(int idx, int type); + bool IsType(int idx, cc8* name, int type); + bool IsValid(); + + bool HasField(int idx, cc8* name); + bool HasField(int idx, int key); + bool HasField(int idx, cc8* name, int type); + bool HasField(int idx, int name, int type); + bool HasKeys(int idx); + + void PushNil(); + void Push(bool value); + void Push(cc8* value); + void Push(double value); + void Push(float value); + void Push(int value); + void Push(u16 value); + void Push(u32 value); + void Push(u64 value); + void Push(uintptr value); + void Push(lua_CFunction value); + void Push(void* data, size_t size); + void Push(const void* value); + + /// + /// 将idx开始的n个push到栈顶,idx会被取正,n向上生长。 + /// + void PushValues(int idx, int n); + + /// + /// 以void** 的形式创建userdata,并将值设置为ptr + /// + void PushPtrUserData(void* ptr); + + void Pop(int n = 1); + + void Settop(int idx); + + template T* GetLuaUserdata(int idx = 1); + + //------------------------------------------------------------------------------------------------------------ + + template T GetValue(int idx, T default_value); + template T GetField(int idx, int key, T value); + template T GetField(int idx, cc8* key, T value); + template void SetField(int idx, cc8* key, T value); + template void SetFieldByIndex(int idx, int key, T value); + + //------------------------------------------------------------------------------------------------------------ + + void DoString(const std::string& code); + void DoFile(const std::string& file); + + //------------------------------------------------------------------------------------------------------------ + // 注册方法 + + /// + /// 注册工厂,适用于普通类,有New方法 + /// + template void RegisterFactory(); + + /// + /// 注册单例,没有New方法 + /// + template void RegisterSingleton(); + + /// + /// 注册枚举 + /// + void RegisterEnum(cc8* name, LuaxEnum* enums); + + /// + /// 注册C函数,注意后面加一行{0, 0} + /// + void RegisterMethods(const luaL_Reg *l); + + /// + /// 注册单个C函数 + /// + void RegisterMethod(cc8* fname, lua_CFunction func); + + /// + /// 把preloader加到package.preload里,当require"libname"时lua的loader_preload根据libname找到preloader直接加载。 + /// 用来实现需要require的时候才加载,并且加载过一次后package.loaded记录下来,下次不会再加载。通过require会调用这个 + /// preloader。 + /// + void RegisterPreloader(cc8* libname, lua_CFunction preloader); + + /// + /// 根据luaL_Reg建立lib table,并在_G和package.loaded建立对libname的索引,指向lib table。 + /// + void RegisterLib(cc8* libname, const luaL_Reg* l); + +#if LUAX_ENABLE_PLAIN_CLASS + /// + /// 注册纯lua类的注册函数,用来创建纯lua类。 + /// + void RegisterPlainClassRegistry(cc8* name); +#endif + +#if LUAX_ENABLE_PLAIN_ENABLE + /// + /// 注册纯lua的枚举,以防止修改枚举值。 + /// + void RegisterPlainEnumRegistry(cc8* name); +#endif + + //------------------------------------------------------------------------------------------------------------ + + private: + + friend class LuaxContext; + + LuaxState(lua_State* state); + LuaxState(const LuaxState& state); + ~LuaxState(); + + /// + /// 屏蔽对LuaxState的地址相关操作 + /// + void* operator &(); + void* operator new(size_t size); + + lua_State* const mState; + + }; + + //-------------------------------------------------------------------------------------------------------------- + // GetValue()模板特化 + + template <> bool LuaxState::GetValue < bool >(int idx, const bool value); + template <> cc8* LuaxState::GetValue < cc8* >(int idx, const cc8* value); + template <> double LuaxState::GetValue < double >(int idx, const double value); + template <> float LuaxState::GetValue < float >(int idx, const float value); + template <> s8 LuaxState::GetValue < s8 >(int idx, const s8 value); + template <> s16 LuaxState::GetValue < s16 >(int idx, const s16 value); + template <> s32 LuaxState::GetValue < s32 >(int idx, const s32 value); + template <> s64 LuaxState::GetValue < s64 >(int idx, const s64 value); + template <> u8 LuaxState::GetValue < u8 >(int idx, const u8 value); + template <> u16 LuaxState::GetValue < u16 >(int idx, const u16 value); + template <> u32 LuaxState::GetValue < u32 >(int idx, const u32 value); + template <> u64 LuaxState::GetValue < u64 >(int idx, const u64 value); + template <> std::string LuaxState::GetValue < std::string >(int idx, const std::string value); + template <> const void* LuaxState::GetValue < const void* >(int idx, const void* value); + template <> int LuaxState::GetValue < int >(int idx, int value); + + + /// + /// 在成员方法里创建LuaxState并对参数进行检查。 + /// +#define LUAX_SETUP(L, params) \ + LuaxRuntime& runtime = LuaxRuntime::Get(); \ + LuaxState& state = runtime[L].state; \ + if(!state.CheckParams(1, params)) return 0 + +#define LUAX_STATE(L) \ + LuaxState& state = LuaxRuntime::Get().GetLuaxState(L) + +} + +#endif \ No newline at end of file diff --git a/source/3rd-party/Luax/luax_state.inl b/source/3rd-party/Luax/luax_state.inl new file mode 100644 index 0000000..06d9350 --- /dev/null +++ b/source/3rd-party/Luax/luax_state.inl @@ -0,0 +1,140 @@ +namespace Luax +{ + + /// + /// 注册工厂,注册class table,以type name为键设置在名称空间上。在注册阶段不会设置元表,等到New方法调用的时候才会。 + /// + template + void LuaxState::RegisterFactory() + { + lua_State* L = mState; + LuaxState& state = *this; + + int top = lua_gettop(L); // namespace table + assert(lua_istable(L, top)); + + // class table + lua_newtable(L); + LuaxNativeClass::RegisterLuaxClass(state); + LuaxNativeClass::RegisterLuaxFactoryClass(state); + T::RegisterLuaxClass(state); + + // 检测T里面是否没有注册必须的方法 +#define _assertmethod(I, NAME) \ + GetField(I, NAME); \ + assert(IsType(-1, LUA_TFUNCTION)); \ + Pop(); + + _assertmethod(-1, "New"); + //_assertmethod(-1, "__gc"); + +#undef _assertmethod + +#if LUAX_ENABLE_NATIVE_EXTEND + // .Extend() + lua_pushvalue(state, -1); // class table + lua_pushcclosure(state, LuaxNativeClass::l_ExtendFactory, 1); + lua_setfield(state, -2, "Extend"); +#endif + + // class["__index"] = class + lua_pushvalue(state, -1); // class table + lua_setfield(state, -2, "__index"); + + LuaxNativeClass::SetLuaxClassTableRef(state, -1); + + cc8* type = T::GetLuaxFactoryName(); + SetField(top, type); + + // reset top + lua_settop(L, top); + + // 后处理 + T::RegisterLuaxPostprocess(state); + } + + /// + /// Singleton + /// + template + void LuaxState::RegisterSingleton() + { + lua_State* L = mState; + LuaxState& state = *this; + + int top = lua_gettop(L); // namespace table + assert(lua_istable(L, top)); + + // class table. + lua_newtable(L); + LuaxNativeClass::RegisterLuaxClass(state); + LuaxNativeClass::RegisterLuaxSingletonClass(state); + T::RegisterLuaxClass(state); + + LuaxNativeClass::SetLuaxClassTableRef(state, -1); + + lua_pushvalue(state, -1); + lua_setfield(state, -2, "__index"); + +#if LUAX_ENABLE_NATIVE_EXTEND + // .Extend() + lua_pushvalue(state, -1); // class table + lua_pushcclosure(state, LuaxNativeClass::l_ExtendSingleton, 1); + lua_setfield(state, -2, "Extend"); +#endif + + cc8* type = T::GetLuaxSingletonName(); + SetField(top, type); + + // reset top + lua_settop(L, top); + + // 后处理 + T::RegisterLuaxPostprocess(state); + } + + template + void LuaxState::SetField(int idx, cc8* key, T value) + { + if (IsTableOrUserdata(idx)) + { + idx = AbsIndex(idx); + this->Push(value); + lua_setfield(mState, idx, key); + } + } + + template + T LuaxState::GetField(int idx, cc8* key, T value) + { + GetField(idx, key); + T result = GetValue < T >(-1, value); + this->Pop(); + + return result; + } + + template + T LuaxState::GetField(int idx, int key, T value) + { + GetField(idx, key); + T result = GetValue < T >(-1, value); + Pop(); + + return result; + } + + template + T* LuaxState::GetLuaUserdata(int idx) + { + void* p = nullptr; + + if (IsType(idx, LUA_TUSERDATA)) + { + p = *(void**)lua_touserdata(mState, idx); + } + + return static_cast(p); + } + +} \ No newline at end of file -- cgit v1.1-26-g67d0