lua-users home
lua-l archive

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


> > the problem is that [luaL_checkudata] this function actually needs to
> > create a new string in order to do the user data name check at all.
> 
> If that is a problem for your application, just write your own
> luaL_checkudata and luaL_newmetatable. You can for instance use void*
> instead of strings and use a static address in your library.

To test the performance of this approach, I've added the code below to
my lcomplex library and ran a simple Mandelbrot test. This tests creates
lots of temporary complex numbers that need to be checked at each step.
Here are the timings: the new scheme takes 70% of the original tinme.

Original scheme -- using strings as keys
0.780u 0.024s 0:00.80 100.0%	0+0k 0+104io 0pf+0w

New scheme -- using light udata as keys
0.540u 0.020s 0:00.55 101.8%	0+0k 0+104io 0pf+0w

Unsafe scheme -- no checking of udata
0.436u 0.012s 0:00.44 100.0%	0+0k 0+0io 0pf+0w

The unsafe scheme uses just this:
#define luaL_checkudata(L,i,s)	lua_touserdata(L,i)

Here is the code, which was based directly on the code in lauxlib.c.
For production, the my_* functions should probably receive the pointer
&mykey, instead of using it directly.

/* udata.c. Include it after lauxlib.h. */

static int mykey=0;

static int my_newmetatable (lua_State *L) {
  lua_pushlightuserdata(L,&mykey);
  lua_rawget(L, LUA_REGISTRYINDEX);
  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_pushlightuserdata(L,&mykey);
  lua_pushvalue(L, -2);
  lua_rawset(L, LUA_REGISTRYINDEX);
  return 1;
}

static void my_getmetatable (lua_State *L) {
  lua_pushlightuserdata(L,&mykey);
  lua_rawget(L, LUA_REGISTRYINDEX);
}

static void *my_checkudata (lua_State *L, int ud, const char *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_pushlightuserdata(L,&mykey);
      lua_rawget(L, LUA_REGISTRYINDEX);  /* get correct metatable */
      if (lua_rawequal(L, -1, -2)) {  /* does it have the correct mt? */
        lua_pop(L, 2);  /* remove both metatables */
        return p;
      }
    }
  }
  luaL_typerror(L, ud, tname);  /* else error */
  return NULL;  /* to avoid warnings */
}

#undef	luaL_getmetatable
#define luaL_getmetatable(L,s)	my_getmetatable(L)
#define luaL_newmetatable(L,s)	my_newmetatable(L)
#define luaL_checkudata(L,i,s)	my_checkudata(L,i,s)