tags:

views:

584

answers:

2

I need to perform operations on Lua tables from C where the tables are treated as lists or queues. Specifically I need to insert an element at the head, and remove the head element, and have the other elements move to accommodate the new element.

This would be simple in straight lua, i'd use table.insert and table.remove. But in C?

There are functions in the Lua C api such as lua_settable, but no equivalents for table.insert and table.remove that are surfaced. It looks like there are internal C functions inside the interpreter called tinsert and tremove, but they are not part of the api.

Do I really have to call out to a lua function that does it for me?

+3  A: 

I believe you can reuse the functions

static int tinsert (lua_State *L)
static int tremove (lua_State *L)

and the macro

#define aux_getn(L,n)   (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))

which are in the ltablib.c. They depend only on Lua's API.

Nick D
thanks. But when I tried tinsert from my code, it fails because the return value of lua_gettop is not what it expects. There are already some values on the stack, so lua_gettop returns something like 24, and that functions expects it to be the number of arguments passed, such as 2 or 3.
sean riley
Do you push, for example, position and value in the Stack before you call tinsert?
Nick D
yeah, the function can be called from different contexts where the stack already has various amounts of stuff on. So I added an extra variable to my version of tinsert for the stack offset and made the internals of my tinsert use that offset. Now it works. thanks.
sean riley
Cheers .
Nick D
+1  A: 

Code not tested, but here's a sketch. You pass the index of the table, and for the insert function, also the index of the value you want to insert. For removal, the value gets pushed on the Lua stack.

#define getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))

void insert_at_head (lua_State *L, int tbl_idx, int val_idx) {
  int e;
  /* shift elements right to make room */
  for (e = getn(L, tbl_idx) + 1; e > 1; e--) {
    lua_rawgeti(L, tbl_idx, e-1);
    lua_rawseti(L, tbl_idx, e);
  }
  lua_pushvalue(L, val_idx);
  lua_rawseti(L, tbl_idx, 1);
}

void remove_from_head_and_push (lua_State *L, int tbl_idx) {
  int e;
  int n = getn(L, tbl_idx);
  if (n == 0)
    return luaL_error("removed from head of empty list");
  lua_rawgeti(L, tbl_idx, 1);  /* push first element */
  /* shift elements left */
  for (e = 2; e < n; e++)
    lua_rawgeti(L, tbl_idx, e);
    lua_rawseti(L, tbl_idx, e-1);
  }
  lua_pushnil(L, val_idx);
  lua_rawseti(L, tbl_idx, n);
}
Norman Ramsey
that is some nice clean code :)
sean riley