lua-users home
lua-l archive

[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)