[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: set a Lua table as metatable of a userdata?
- From: "lists@..." <lists@...>
- Date: Wed, 16 Aug 2006 15:47:35 -0700
Hi,
Right - thanks. I just did the same thing (trying it in Lua first
before C), which helped a great deal to understand this. Also I had a
bug in my newInstance, the userdata & table were the wrong way around
on the stack for lua_setmetatable. It's working nicely I think now,
though I noticed that the __gc method is only being called if I
install it in the instance table (mt1), not the class table (mt2) as
below.
It currently looks something like this (where mt1 = instance table,
mt2 = class table):
static int newTest(lua_State * L)
{
lua_newtable(L); // mt1
// push a temporary variable into the imt
lua_pushstring(L, "instancevar");
lua_pushnumber(L, 0.5);
lua_settable(L, -3);
// set mt1.__index = mt1
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
// set mt1.__newindex = mt1
lua_pushstring(L, "__newindex");
lua_pushvalue(L, -2);
lua_settable(L, -3);
// get class metatable (mt2) & assign to instance metatable (mt1)
luaL_getmetatable(L, classname);
lua_setmetatable(L, -2); // setmetatable(mt1, mt2)
// create the full userdata pointer
void ** udata = (void **)lua_newuserdata (L, sizeof(void **)); //
it's now on the stack
*udata = new Test(); // have the fulluserdata point to the C++
instance
// move the pointer to stack index 1 & assign the input table to be
the metatable of the userdata
lua_insert(L, 1);
lua_setmetatable(L, -2); // setmetatable(udata, mt1)
// now return the userdatum
return 1;
}
The class registration looks something like this:
/*
Register a class
*/
static int registerClass(lua_State * L, const char * classname, const
luaL_Reg *methods, lua_CFunction newfn, lua_CFunction deletefn)
{
// create class metatable (only visible to C API)
luaL_newmetatable(L, classname); // mt2
// install methods
luaL_openlib(L, NULL, methods, 0); /* NULL means push the methods
into the metatable */
// mt2.__index = mt2
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
// push a temporary variable into the imt
lua_pushstring(L, "classvar");
lua_pushnumber(L, 0.25);
lua_settable(L, -3);
// note: mt2.__newindex is not changed
// install destructor
lua_pushstring(L, "__gc");
lua_pushcfunction(L, deletefn);
lua_settable(L, -3); /* metatable.__gc = deletefn */
// create constructor
lua_pushcfunction(L, newfn);
lua_setglobal(L, classname);
return 1; // default luaopen_ behaviour is to leave the metatable on
the stack
}
Some test code in Lua:
a = NumArray()
b = NumArray()
print("a", a)
print("b", b)
a.temp = 1
b.temp = 2
print("a.temp", a.temp)
print("b.temp", b.temp)
print("a.instancevar", a.instancevar)
print("b.instancevar", b.instancevar)
a.instancevar = 3
print("a.instancevar", a.instancevar)
print("b.instancevar", b.instancevar)
print("a.classvar", a.classvar)
print("b.classvar", b.classvar)
-- this will not change classvar, it will override it with an
instance variable
b.classvar = 4
print("a.classvar", a.classvar)
print("b.classvar", b.classvar)
Output:
a userdata: 0x308c04
b userdata: 0x308cb4
a.temp 1
b.temp 2
a.instancevar 0.5
b.instancevar 0.5
a.instancevar 3
b.instancevar 0.5
a.classvar 0.25
b.classvar 0.25
a.classvar 0.25
b.classvar 4