[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua 5 and tags
- From: Vincent Penne <ziggy@...>
- Date: Mon, 26 Jul 2004 12:20:26 +0200
Mark Hamburg wrote:
on 7/25/04 2:16 PM, Vincent Penne at ziggy@sashipa.com wrote:
Here is the code that do what I suggest :
void *luaL_checkudata_ref(lua_State *L, int ud, int ref, char *msg)
{
void *u;
if (lua_getmetatable(L, ud)) && (lua_getref(L, ref), 1) &&
lua_rawequal(L, -1, -2) &&
(u = lua_touserdata(L, ud))) {
lua_pop(L, 2);
return u;
}
luaL_argerror(L, 0, msg); /* Never returns. */
return NULL;
}
The only problem with this code is that if you create multiple Lua universes
-- i.e., independent Lua states as opposed to multiple Lua threads -- then
you can't rely on sharing a C global for the ref to the metatable.
Actually, what I do is put all the references not into global variables
but into a C structure. And I instantiate one of these C binding
structure for each lua state. Then to get that C binding structure, I
can either store it as upvalue of my function, either have a function
that map from a lua state adress to the binding structure. It is one of
the case where light userdata are very handy actually ! When you use
them as upvalue it's completely safe.
One other approach would be to assume that you could use location 1 in the
metatable and do a lua_rawgeti to fetch it and test that it held an
appropriate userdata value.
Untested...
void *luaL_checkudata_ud1 (lua_State *L, int ud, void *tident, char *msg)
{
void *u = lua_touserdata(L, ud);
if( u && lua_getmetatable(L, ud) ) {
lua_rawgeti(L, -1, 1);
if( lua_touserdata(L, -1) == tident ) {
lua_pop(L, 2); /* Restore stack before fetching */
return u;
}
}
luaL_argerror(L, ud, msg);
return NULL;
}
That's an idea ! I'm going to test that and see how it performs compared
to the other method.
However, what I do in my binding (it is automatically generated) is a
bit more complicated because it's a C++ binding, and I have to take care
of type casting. My functions need to check the type in a more complex
way because they can accept the base type or any of it's derivated type.
To do that, I construct a table of compatible type for each type. I
store a reference on these compatible type table and try to index it
with the metatable of the actual argument of the function, if the result
is not nil then I know the type I received as input is compatible. Here
is how my function looks like :
The lua_type_t structure comes from a superstructure (my binding
structure) containing one of this lua_type_t object for each existing
type, and the binding structure as been stored as upvalue for example.
static void * _lua_to_class(lua_State * __S__, int pos, lua_type_t *
wanted_type)
{
int iscompat;
#if 1 /* this part can be ifdefed out, but it's faster to check the
special case where wanted type is exactly the given type */
if (!lua_getmetatable(__S__, pos)) {
return 0;
}
lua_getref(__S__, wanted_type->metatable);
iscompat = lua_rawequal(__S__, -1, -2);
lua_pop(__S__, 2);
if (iscompat) {
return *(void * *)lua_touserdata(__S__, pos);
} else
#endif
{ /* from now on we check it is a compatible (derivated) type */
lua_getref(__S__, wanted_type->cttable); /* get the compatible type
table */
lua_getmetatable(__S__, pos);
lua_gettable(__S__, -2); /* try to get
cttable[metatable] */
iscompat = !lua_isnil(__S__, -1);
lua_pop(__S__, 2);
if (iscompat)
return *(void * *)lua_touserdata(__S__, pos);
/* printf("bind-lua : could not cast from %s to %s !\n", */
/* tn, wanted_type->name); */
return 0;
}
}