lua-users home
lua-l archive

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

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.