lua-users home
lua-l archive

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


On Thu, 13 Sep 2001, Michael Cuddy wrote:

> What is the recommended course of action (maybe I just don't get
> "the model" ;-)

The best thing is to avoid pushing the same pointer twice (e.g. you can
keep a reference to its userdata inside the structure pointed by the
pointer).

Otherwise, the following function should model the old behavior, with some
restrictions (see below).

void lua_pushusertag (lua_State *L, void *p, int tag) {
  char buff[50];
  sprintf(buff, "%p(%d)", p, tag);  /* create a key */
  lua_getregistry(L);  /* stack: registry */
  lua_pushstring(L, "userdata map");
  lua_gettable(L, -2);  /* stack: udata_map registry */
  if (lua_isnil(L, -1)) {  /* no udata_map? */
    lua_pop(L, 1);  /* stack: registry */
    lua_newtable(L);  /* stack: new_udata_map registry */
    lua_setweakmode(L, LUA_WEAK_VALUE);
    lua_pushstring(L, "userdata map");
    lua_pushvalue(L, -2);  /* stack: udata_map string udata_map registry */
    lua_settable(L, -4);  /* stack: udata_map registry */
  }
  lua_pushstring(L, buff);  /* stack: buff udata_map registry */
  lua_gettable(L, -2);  /* stack: udata_map[buff] udata_map registry */
  if (lua_isnil(L, -1)) {  /* no previous udata with this pointer? */
    lua_pop(L, 1);
    lua_lua_newuserdatabox(L, p);  /* stack: newud udata_map registry */
    lua_settag(L, tag);
    lua_pushstring(L, buff);  /* stack: buff newud udata_map registry */
    lua_pushvalue(L, -2);  /* stack: newud buff newud udata_map registry */
    lua_settable(L, -4);  /* stack: newud udata_map registry */
  }
  lua_remove(L, -2);  /* stack: udata_map[buff] registry */
  lua_remove(L, -2);  /* stack: udata_map[buff] */
}


Comments:

* code not tested.

* it does not handle LUA_ANYTAG.

* it may be slow.

* you must first create a table with key "userdata map" in the registry;
this table must have weak values (otherwise those userdata will never be
collected).

* you can have a simpler and faster implementation if you use only the
pointer as the key (collapsing eventual userdata with equal pointers but
different tags). In this case, you can use "(int)p" as the key into table
registry["userdata map"], and so you can also use lua_rawseti/lua_rawgeti.

-- Roberto