lua-users home
lua-l archive

Re: alternative udata checking

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


On Thursday 01, Luiz Henrique de Figueiredo wrote:
> Lua 5.2 introduces lua_rawgetp and lua_rawsetp and this makes it simpler to
> use pointers instead of strings as udata types in the registry.
> 
> The attached file extends the udata checking in lauxlib.c to use pointers.
> To test it, just #include "udata.c" in your C module. This file assumes
> that you only handle *one* type of udata per module.
There is a bug in the code. The value passed as tname is a pointer to an 
'int' not a string, if typeerror() is called it will try to print that 'int' 
as a string. 'mykey' could be changed to a string it doesn't have to be an 
'int'. Also the value of the string could be provided by the code that 
includes udata.c using a #define. See the attached fixed version (un-tested).
> I did a quick test with my lrandom and I got a 15% speedup. I'd like to
> hear about the experience of others with this scheme.
I have avoided using luaL_checkudata for some time in my C modules and 
bindings generator. I had bench marked the performance cost of the string 
interning of luaL_checkudata, but I don't remember the results.
I still use luaL_newmetatable to create the metatable but store a reference to 
it in the REGISTRY using a lightuserdata key. Hmm, I should maybe stop using 
luaL_newmetatable to avoid name clashes, or atleast add some prefix.
It would be interesting to see a survey of the stuff that gets added to the 
global REGISTRY by different modules.
> The main idea is applicable to 5.1 but you'll need to use
> lua_pushlightudata etc explicitly. See
> http://lua-users.org/lists/lua-l/2010-11/msg00151.html .
-- 
Robert G. Jakabosky
/*
** {======================================================
** Userdata's metatable manipulation
** =======================================================
*/
static int typeerror (lua_State *L, int narg, const char *tname) {
 const char *msg = lua_pushfstring(L, "%s expected, got %s",
 tname, luaL_typename(L, narg));
 return luaL_argerror(L, narg, msg);
}
LUALIB_API int luaL_newmetatablep (lua_State *L, const void *tname) {
 lua_rawgetp(L, LUA_REGISTRYINDEX, tname); /* get registry.name */
 if (!lua_isnil(L, -1)) /* name already in use? */
 return 0; /* leave previous value on top, but return 0 */
 lua_pop(L, 1);
 lua_newtable(L); /* create metatable */
 lua_pushvalue(L, -1);
 lua_rawsetp(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
 return 1;
}
LUALIB_API void luaL_setmetatablep (lua_State *L, const void *tname) {
 lua_rawgetp(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
 lua_setmetatable(L, -2);
}
LUALIB_API void *luaL_testudatap (lua_State *L, int ud, const void *tname) {
 void *p = lua_touserdata(L, ud);
 if (p != NULL) { /* value is a userdata? */
 if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
 lua_rawgetp(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
 if (!lua_rawequal(L, -1, -2)) /* not the same? */
 p = NULL; /* value is a userdata with wrong metatable */
 lua_pop(L, 2); /* remove both metatables */
 return p;
 }
 }
 return NULL; /* value is not a userdata with a metatable */
}
LUALIB_API void *luaL_checkudatap (lua_State *L, int ud, const void *tname) {
 void *p = luaL_testudatap(L, ud, tname);
 if (p == NULL) typeerror(L, ud, tname);
 return p;
}
/* }====================================================== */
#ifndef MY_MODULE_NAME
#define MY_MODULE_NAME "GenericModuleName"
#endif
static char *mykey=MY_MODULE_NAME;
#define luaL_getmetatable(L,n)	lua_rawgetp(L,LUA_REGISTRYINDEX,mykey)
#define luaL_newmetatable(L,n)	luaL_newmetatablep(L,mykey)
#define luaL_setmetatable(L,n)	luaL_setmetatablep(L,mykey)
#define luaL_testudata(L,i,n)	luaL_testudatap(L,i,mykey)
#define luaL_checkudata(L,i,n)	luaL_checkudatap(L,i,mykey)

AltStyle によって変換されたページ (->オリジナル) /