lua-users home
lua-l archive

Possible API, vaguely related to string efficiency

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


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

AltStyle によって変換されたページ (->オリジナル) /