[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Using a luaL_Buffer while traversing a table
- From: Luiz Henrique de Figueiredo <lhf@...>
- Date: Wed, 12 Aug 2009 17:30:06 -0300
> Hi. Does anyone have some tips (or code, preferable :D) on how to
> traverse a table using lua_next while adding stuff to a luaL_Buffer ?
> The fact that the buffer operations may change my stack top is giving me
> trouble. I thought of saving the positions of the key and value after
> lua_next, adding stuff to the buffer and then lua_remove(L, value_pos)
> and bringing the key to the top of the stack. I haven't tried this, but
> I'm afraid that it might break the buffer operations.
I had a similar problem in my take on unrope for ropes implemented as
Lua tables. In the end I had to reserve some stack space before the
Lua buffer data. The final C code is below. The original thread started
at http://lua-users.org/lists/lua-l/2008-12/msg00055.html but the initial
versions had bugs...
/*
* lrope.c
* provides unrope
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 06 Dec 2008 00:13:56
* This code is hereby placed in the public domain.
*/
#include "lua.h"
#include "lauxlib.h"
#define MAXLEVEL 30
static int doconcat (lua_State *L, luaL_Buffer *b, int t, int needsep) {
int i;
if (t>MAXLEVEL+1) luaL_error(L,"table too deep for "LUA_QL("unrope"));
for (i=1;; i++)
{
lua_rawgeti(L,t,i);
switch (lua_type(L,-1))
{
case LUA_TNIL:
lua_pop(L,1);
return needsep;
case LUA_TNUMBER:
case LUA_TSTRING:
if (needsep) {lua_pushvalue(L,1); luaL_addvalue(b);}
luaL_addvalue(b);
needsep=1;
break;
case LUA_TTABLE:
lua_replace(L,t+1);
needsep=doconcat(L,b,t+1,needsep);
break;
default:
lua_pop(L,1);
}
}
}
static int unrope (lua_State *L) {
luaL_Buffer b;
luaL_checktype(L,1,LUA_TTABLE);
lua_settop(L,2);
if (lua_isnil(L,2)) {lua_pushliteral(L,""); lua_replace(L,2);}
else luaL_checkstring(L,2);
lua_insert(L,1);
luaL_checkstack(L,MAXLEVEL-1+LUA_MINSTACK,"cannot grow stack");
lua_settop(L,MAXLEVEL+1);
luaL_buffinit(L,&b);
doconcat(L,&b,2,0);
luaL_pushresult(&b);
return 1;
}
LUALIB_API int luaopen_rope (lua_State *L) {
lua_register(L,"unrope",unrope);
return 0;
}