[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Possible API, vaguely related to string efficiency
- From: Rici Lake <lua@...>
- Date: Thu, 29 Mar 2007 17:10:29 -0500
One thing I've been musing about, with respect to strings, is
exemplified by the following function in llex.c:
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
TString *ts = luaS_newlstr(L, str, l);
TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */
if (ttisnil(o))
setbvalue(o, 1); /* make sure `str' will not be collected */
return ts;
}
This function is used to temporarily stash a string into a hash table
(whose address is at ls->fs->h) in order to avoid it being garbage
collected during the parse.
Doing that with the standard API is quite a lot more verbose. Here's
one way:
static const char *stash_string (lua_State *L, int table_index,
const char *str, size_t len) {
const char *rv;
lua_pushlstring(L, str, len);
lua_pushvalue(L, -1); /* In case we need it again */
rv = lua_tostring(L, -1);
lua_rawget(L, table_index);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
lua_pushboolean(L, 1);
lua_rawset(L, table_index);
}
else {
lua_pop(L, 2);
}
return rv;
}
This requires 6 or 8 API calls, which compares rather unfavourably
with the optimized (internal) version in llex.c; my tests seem to
indicate that the execution of index2adr in lapi.c is a major
bottleneck.
This could be improved considerably with the API call
lua_haskey(L, index), which looks up the key at the top of
the stack in the table at 'index' and returns a boolean
without popping the key.
It would also be nice if lua_pushlstring returned a pointer
to the (interned) string.
Then the above could be written:
const char *stash_string (lua_State *L, int table_index,
const char *str, size_t len) {
const char *rv = lua_pushlstring(L, str, len);
if (lua_haskey(L, table_index))
lua_pop(L, 1);
else {
lua_pushboolean(L, 1);
lua_rawset(L, table_index);
}
return rv;
}
This cuts the number of API calls down to 3 or 4, and also
makes it easier to do default values:
if (!lua_haskey(L, table_index)) {
lua_pushvalue(L, -1);
/* push default value, eg:
* lua_newtable(L);
* or
* lua_pushinteger(L, 0);
*/
lua_rawset(L, table_index);
}
lua_rawget(L, table_index);