This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
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. |