[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: how to use lmem.h ?
- From: Mark Hamburg <mark@...>
- Date: Sat, 21 Feb 2009 22:21:35 -0800
On Feb 21, 2009, at 8:55 PM, Alex Davies wrote:
lua_Alloc f = lua_getallocf(L, &ud);
slen = luaL_optlong(L, 2, slen);
buf = (*f)(ud, NULL, 0, (2 * slen));
dlen = apreq_quote(buf, src, slen);
lua_pushlstring(L, buf, dlen);
(*f)(ud, buf, (2 * slen), 0);
return 1;
Is there something wrong with this code ?
Just because you asked, there's a very minor problem which is common
in a lot of code - a memerr on the pushlstring will result in a
memory leak. No neat fix though.
No tested code here, but a thought.
You can avoid the error problem by using a userdata and letting the GC
collect it. That gets expensive relative to malloc/free if you do it
every time since the GC is necessarily more expensive than the free.
We could work around that, however, by doing the following:
1. Store the userdata pointer via a weak cache table entry and store
the length in a static variable.
2. The code now checks the cached length and if it is long enough
tries to fetch the cached userdata and put it on the stack. If that
fails or if the length isn't long enough, it allocates a new userdata.
The effect is that the buffer will only get allocated a few times and
then stick around until GC.
The code might run something like this:
slen = luaL_optlong( L, 2, slen );
lua_pushlightuserdata( L, kTempBufferTableKey ); // A fully weak table
lua_gettable( L, LUA_REGISTRYINDEX );
buf = NULL;
if( 2 * slen <= g_stringBufferLength ) {
lua_pushlightuserdata( L, kThisBufferKey );
lua_gettable( L, -2 );
buf = lua_touserdata( L, -1 );
if( buf == NULL )
lua_pop( L, 1 );
}
if( buf == NULL ) {
buf = lua_newuserdata( L, 2 * slen );
lua_pushlightuserdata( L, kThisBufferKey );
lua_pushvalue( L, -2 );
lua_settable( L, -4 );
g_stringBufferLength = 2 * slen;
}
dlen = apreq_quote( buf, src, slen );
lua_pushlstring( L, buf, dlen );
return 1;
Together with some startup code that sets
LUA_REGISTRY[ kTemBufferTableKey ] = setmetatable( { }, { __mode =
"kv" } )
If we don't need to deal with multiple buffers, we could just use a
fixed index in this table to store the buffer thereby speeding access.
If we need to use the table in re-entrant situations, then we need to
clear the entry while processing.
Mark