Skip to content

Instantly share code, notes, and snippets.

@EvanMu96
Created May 8, 2020 09:18
Show Gist options
  • Save EvanMu96/7e169117472308c7fe59fc000101b0c6 to your computer and use it in GitHub Desktop.
Save EvanMu96/7e169117472308c7fe59fc000101b0c6 to your computer and use it in GitHub Desktop.
basic lua binding header helper
#include "lunatic.h"
#include <lua-5.1/lua.hpp>
#include <stdio.h>
class LuaTest {
public:
LuaTest() {}
LuaTest(lua_State * L) {}
static const char className[];
static Lunatic<LuaTest>::RegType methods[];
int TestString(lua_State * L) {printf("this string is printed by c++\n");return 0;}
};
class LuaTest2 {
public:
LuaTest2() {}
LuaTest2(lua_State * L) {}
static const char className[];
static Lunatic<LuaTest2>::RegType methods[];
int TestString(lua_State * L) {printf("this string is printed by c++\n");return 0;}
};
const char LuaTest::className[] = "LuaTest";
const char LuaTest2::className[] = "LuaTest2";
#define method(class, name) {#name, &class::name}
Lunatic<LuaTest>::RegType LuaTest::methods[] = {
method(LuaTest, TestString), {nullptr, nullptr}
};
Lunatic<LuaTest2>::RegType LuaTest2::methods[] = {
method(LuaTest2, TestString), {nullptr, nullptr}
};
int main() {
lua_State * L = luaL_newstate();
luaL_openlibs(L);
// ok to bind multiple classes
Lunatic<LuaTest>::Register(L);
Lunatic<LuaTest2>::Register(L);
// do_file better to use a absolute path
luaL_dofile(L, "/Users/******************/test.lua");
lua_close(L);
return 0;
}
/*
test.lua
test = LuaTest()
test:TestString()
print("test string in lua")
*/
#pragma once
#include <lua-5.1/lua.hpp>
template <typename T>
class Lunatic {
typedef struct {T * pt;} userDataType;
public:
typedef int (T::*mfp)(lua_State * L);
typedef struct{const char * name; mfp mfunc;} RegType;
static void Register(lua_State * L) {
// 用一个tabble 保存栈索引,这个方法表就是要用来保存要导出的成员函数
lua_newtable(L);
int methods = lua_gettop(L);
// 在注册表中新建一个元素, metatable保存其栈索引
luaL_newmetatable(L, T::className);
int metatable = lua_gettop(L);
// 全局表(T::className)=methods表
lua_pushstring(L, T::className);
lua_pushvalue(L, methods);
lua_settable(L, LUA_GLOBALSINDEX);
// 设置metatable 的_metatable元事件
// 将metatable封装起来,防止外部的获取和修改
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methods);
lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methods);
lua_settable(L, metatable);
// 设置元表 __tostring和__gc (gc暂且不实现, 我们希望对象的生命周期完全在c++)
lua_pushliteral(L, "__tostring");
lua_pushcfunction(L, tostring_T);
lua_settable(L, metatable);
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_T);
lua_settable(L ,metatable);
// 设置mt的_call metamethod a()时触发
lua_newtable(L);
int mt = lua_gettop(L);
lua_pushliteral(L, "__call");
lua_pushcfunction(L, new_T);
lua_pushliteral(L, "new");
lua_pushvalue(L, -2);
lua_settable(L, methods);
lua_settable(L, mt);
lua_setmetatable(L, methods);
// fill method table with methods from class T
for(RegType *l = T::methods; l->name; l++) {
lua_pushstring(L, l->name);
lua_pushlightuserdata(L, (void*)l);
lua_pushcclosure(L, thunk, 1); // 创建closure
lua_settable(L, methods);
}
lua_pop(L, 2); // drop metatabke abd method table
}
static T * check(lua_State * L, int narg) {
userDataType * ud = static_cast<userDataType*> (luaL_checkudata(L, narg, T::className));
if(nullptr == ud) {
luaL_typerror(L, narg, T::className);
}
return ud->pt;
}
private:
Lunatic();
static int thunk(lua_State * L) {
T * obj = check(L, 1);
lua_remove(L, 1); //remove self
RegType * l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
return (obj->*(l->mfunc))(L); //call member function
}
static int new_T(lua_State * L) {
lua_remove(L, 1);
T * obj = new T(L);
userDataType *ud = static_cast<userDataType*>(lua_newuserdata(L, sizeof(userDataType)));
ud->pt = obj; // store pointer to object in userdata
luaL_getmetatable(L, T::className);
lua_setmetatable(L, -2);
return 1;
}
static int tostring_T (lua_State * L) {
char buff[32];
userDataType * ud = static_cast<userDataType*>(lua_touserdata(L, 1));
T * obj = ud->pt;
sprintf(buff, "%p", obj);
lua_pushfstring(L, "%s (%s)", T::className, buff);
return 1;
}
static int gc_T(lua_State * L) {
userDataType * ud = static_cast<userDataType*>(lua_touserdata(L, 1));
T * obj = ud->pt;
delete obj; // call dtor
return 0;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment