[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: alternative udata checking
- From: "Robert G. Jakabosky" <bobby@...>
- Date: Thu, 1 Dec 2011 23:46:18 -0800
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)