This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <new> | |
extern lua_State *L; | |
class MyClass | |
{ | |
public: | |
MyClass() | |
{ | |
value = 0; | |
puts("MyClass::MyClass called"); | |
} | |
~MyClass() | |
{ | |
puts("MyClass::~MyClass called"); | |
} | |
int value; | |
}; | |
static const char* myClassName = "MyClass"; | |
#define GET_MYCLASS \ | |
MyClass* p = (MyClass*)luaL_checkudata(L, 1, myClassName); \ | |
if (!p) { return 0; } | |
void BindMyClass() | |
{ | |
static struct luaL_Reg methods[] = | |
{ | |
{ "__gc", [](lua_State* L) { GET_MYCLASS p->~MyClass(); return 0; } }, | |
{ "SetValue", [](lua_State* L) { GET_MYCLASS p->value = (int)lua_tointeger(L, -1); return 0; } }, | |
{ "GetValue", [](lua_State* L) { GET_MYCLASS lua_pushinteger(L, p->value); return 1; } }, | |
{ nullptr, nullptr }, | |
}; | |
BindClass(L, myClassName, methods, [](lua_State* L) { new (lua_newuserdata(L, sizeof(MyClass))) MyClass; return 1; }); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static int CreateCppClassInstance(lua_State* L) | |
{ | |
const char* className = lua_tostring(L, lua_upvalueindex(1)); | |
lua_CFunction actualInstanceCreator = lua_tocfunction(L, lua_upvalueindex(2)); | |
actualInstanceCreator(L); | |
luaL_getmetatable(L, className); | |
lua_setmetatable(L, -2); | |
return 1; | |
} | |
static void CreateClassMetatable(lua_State* L, const char* className, luaL_Reg methods[]) | |
{ | |
luaL_newmetatable(L, className); | |
lua_pushstring(L, "__index"); | |
lua_pushvalue(L, -2); | |
lua_settable(L, -3); | |
luaL_setfuncs(L, methods, 0); | |
lua_pop(L, 1); | |
} | |
static void CreateClassInstanceCreator(lua_State* L, const char* className, lua_CFunction creator) | |
{ | |
lua_pushstring(L, className); | |
lua_pushcfunction(L, creator); | |
lua_pushcclosure(L, CreateCppClassInstance, 2); | |
lua_setglobal(L, className); | |
} | |
void BindClass(lua_State* L, const char* className, luaL_Reg methods[], lua_CFunction creator) | |
{ | |
CreateClassMetatable(L, className, methods); | |
CreateClassInstanceCreator(L, className, creator); | |
} |
C++にだけ慣れていると奇妙に見えるのはCreateCppClassInstanceです。これはLuaから呼べる関数型をしていますが単独では呼べません。upvalueという領域にクラス名とクラスのインスタンス生成を行う関数を結び付けてクロージャを生成しておくことで初めて関数として呼べるようになっています。そのクロージャを生成してクラス名と同名のグローバル関数を登録する部分がCreateClassInstanceCreatorです。
このようにしてクラスの種類数だけクロージャを生成することで、どんな種類のクラスインスタンスもCreateCppClassInstanceに生成させることが出来るようになります。
ところで、CreateCppClassInstanceのactualInstanceCreatorはlua_CFunction型として取り出して、直接CからactualInstanceCreatorを呼び出しています。これはBindClassの引数として受け取っているcreatorです。ということは、Luaが直接creatorを呼び出すことは無いのでlua_CFunction型を使う必要は無いということです。lightuserdataとして任意の型の関数にしても問題なさそうです。
No comments:
Post a Comment