lua-users home
lua-l archive

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


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.

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.

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 .
/*
** {======================================================
** 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;
}

/* }====================================================== */

static int mykey=0;

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