lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


>>>>> "Luiz" == Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br> writes:

 Andrew> I always use my own equivalents for luaL_setmetatable and
 Andrew> luaL_checkudata that work off lightuserdata keys instead.

 Luiz> Could you please share your code? It may be useful to others.
 Luiz> See also this thread:
 Luiz> http://lua-users.org/lists/lua-l/2011-12/msg00039.html

So I've done it in essentially two different ways: one is to copy
something close to the structure of luaL_checkudata, but passing in a
pointer to a (non-const!) string which becomes the name only for
diagnostic purposes, and the address of the string is used as the
registry key. This does require making the name an actual variable
rather than (say) a #define, but it can be kept private within the
module on all sane platforms. (Using a non-const string means the
compiler/linker can't merge definitions, so the address is unique.)

Examples of this approach, snipped from
https://github.com/RhodiumToad/pllua-ng/

void pllua_newmetatable(lua_State *L, char *objtype, luaL_Reg *mt)
{
	lua_newtable(L);
	luaL_setfuncs(L, mt, 0);
	lua_pushstring(L, objtype);
	lua_setfield(L, -2, "__name");
	lua_pushboolean(L, 1);
	lua_setfield(L, -2, "__metatable");
	lua_pushvalue(L, -1);
	lua_rawsetp(L, LUA_REGISTRYINDEX, objtype);
}

void *pllua_toobject(lua_State *L, int nd, char *objtype)
{
	void *p = lua_touserdata(L, nd);
	if (p != NULL)
	{
		if (lua_getmetatable(L, nd))
		{
			lua_rawgetp(L, LUA_REGISTRYINDEX, objtype);
			if (!lua_rawequal(L, -1, -2))
				p = NULL;
			lua_pop(L, 2);
			return p;
		}
	}
	return NULL;
}

void *pllua_checkobject(lua_State *L, int nd, char *objtype)
{
	void *p = pllua_toobject(L, nd, objtype);
	if (!p)
		pllua_type_error(L, objtype);
	return p;
}

used like:

char PLLUA_ACTIVATION_OBJECT[] = "activation object";

static int pllua_dump_activation(lua_State *L)
{
	pllua_func_activation *act = pllua_checkobject(L, 1, PLLUA_ACTIVATION_OBJECT);
// body snipped
}

The other method I've used (which I may have posted before) is to use a
data structure that defines properties of an object type (size to
allocate, methods and metamethods to define, class name, parent class
for simple single inheritance, etc., and use the address of this as the
registry key. See code at

https://github.com/RhodiumToad/flspawn/blob/main/simple_class.c

An example class definition would look like (from auto_close.c in the
same repo):

static RegMeta auto_close_meta = {
	.name = "auto_close",
	.obj_size = 0,
	.num_uservalues = 1,
	.metamethods = (luaL_Reg[]){
		{ "__close", auto_close_close },
		{ "__call", auto_close_get },
		{ NULL, NULL }
	},
	.methods = (luaL_Reg[]){
		{ "get", auto_close_get },
		{ "release", auto_close_release },
		{ "close", auto_close_close },
		{ NULL, NULL }
	}
};

-- 
Andrew.