![]() |
Programming in Lua | ![]() |
Part IV. The C API Chapter 27. Techniques for Writing C Functions |
"Array", in Lua, is just a name for a table used in a specific way.
We can manipulate arrays using the same functions
we use to manipulate tables,
namely lua_settable
and lua_gettable
.
However, contrary to the general philosophy of Lua,
economy and simplicity,
the API provides special functions for array manipulation.
The reason for that is performance:
Frequently we have an array access operation
inside the inner loop of an algorithm (e.g., sorting),
so that any performance gain in this operation
can have a big impact on the overall performance of the function.
The functions that the API provides for array manipulation are
void lua_rawgeti (lua_State *L, int index, int key); void lua_rawseti (lua_State *L, int index, int key);The description of
lua_rawgeti
and lua_rawseti
is a little confusing,
as it involves two indices:
index
refers to where the table is in the stack;
key
refers to where the element is in the table.
The call lua_rawgeti(L, t, key)
is equivalent to the sequence
lua_pushnumber(L, key); lua_rawget(L, t);when
t
is positive
(otherwise, you must compensate for the new item in the stack).
The call lua_rawseti(L, t, key)
(again for t
positive)
is equivalent to
lua_pushnumber(L, key); lua_insert(L, -2); /* put `key' below previous value */ lua_rawset(L, t);Note that both functions use raw operations. They are faster and, anyway, tables used as arrays seldom use metamethods.
As a concrete example of the use of these functions,
we could rewrite the loop body
from our previous l_dir
function from
lua_pushnumber(L, i++); /* key */ lua_pushstring(L, entry->d_name); /* value */ lua_settable(L, -3);to
lua_pushstring(L, entry->d_name); /* value */ lua_rawseti(L, -2, i++); /* set table at key `i' */
As a more complete example, the following code implements the map function: It applies a given function to all elements of an array, replacing each element by the result of the call.
int l_map (lua_State *L) { int i, n; /* 1st argument must be a table (t) */ luaL_checktype(L, 1, LUA_TTABLE); /* 2nd argument must be a function (f) */ luaL_checktype(L, 2, LUA_TFUNCTION); n = luaL_getn(L, 1); /* get size of table */ for (i=1; i<=n; i++) { lua_pushvalue(L, 2); /* push f */ lua_rawgeti(L, 1, i); /* push t[i] */ lua_call(L, 1, 1); /* call f(t[i]) */ lua_rawseti(L, 1, i); /* t[i] = result */ } return 0; /* no results */ }This example introduces three new functions. The
luaL_checktype
function (from lauxlib.h
)
ensures that a given argument has a given type;
otherwise, it raises an error.
The luaL_getn
function gets the size
of the array at the given index
(table.getn
calls luaL_getn
to do its job).
The lua_call
function does an unprotected call.
It is similar to lua_pcall
,
but in case of errors it throws the error,
instead of returning an error code.
When you are writing the main code in an application,
you should not use lua_call
,
because you want to catch any errors.
When you are writing functions, however,
it is usually a good idea to use lua_call
;
if there is an error,
just leave it to someone that cares about it.
Copyright © 2003-2004 Roberto Ierusalimschy. All rights reserved. |
![]() |
![]() |