lua

A copy of the Lua development repository
Log | Files | Refs | README

commit af4721f7a37834e5b5469f342caed0629932a4aa
parent 018e50ad7f24aa8f8f4afe50d513964624c4ca35
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Tue,  9 Apr 2002 17:18:44 -0300

library with table manipulation functions

Diffstat:
Altablib.c | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 308 insertions(+), 0 deletions(-)

diff --git a/ltablib.c b/ltablib.c @@ -0,0 +1,308 @@ +/* +** $Id: $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + + +#include <stddef.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "luadebug.h" +#include "lualib.h" + + + + +static int luaB_foreachi (lua_State *L) { + int n, i; + luaL_check_type(L, 1, LUA_TTABLE); + luaL_check_type(L, 2, LUA_TFUNCTION); + n = lua_getn(L, 1); + for (i=1; i<=n; i++) { + lua_pushvalue(L, 2); /* function */ + lua_pushnumber(L, i); /* 1st argument */ + lua_rawgeti(L, 1, i); /* 2nd argument */ + lua_rawcall(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 1); /* remove nil result */ + } + return 0; +} + + +static int luaB_foreach (lua_State *L) { + luaL_check_type(L, 1, LUA_TTABLE); + luaL_check_type(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first key */ + for (;;) { + if (lua_next(L, 1) == 0) + return 0; + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_rawcall(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 2); /* remove value and result */ + } +} + + +static void aux_setn (lua_State *L, int t, int n) { + lua_pushliteral(L, "n"); + lua_pushnumber(L, n); + lua_rawset(L, t); +} + + +static int luaB_getn (lua_State *L) { + luaL_check_type(L, 1, LUA_TTABLE); + lua_pushnumber(L, lua_getn(L, 1)); + return 1; +} + + +static int luaB_tinsert (lua_State *L) { + int v = lua_gettop(L); /* number of arguments */ + int n, pos; + luaL_check_type(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + if (v == 2) /* called with only 2 arguments */ + pos = n+1; + else { + v = 3; /* function may be called with more than 3 args */ + pos = luaL_check_int(L, 2); /* 2nd argument is the position */ + } + if (pos > n+1) n = pos-1; + aux_setn(L, 1, n+1); /* t.n = n+1 */ + for (; n>=pos; n--) { + lua_rawgeti(L, 1, n); + lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ + } + lua_pushvalue(L, v); + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int luaB_tremove (lua_State *L) { + int pos, n; + luaL_check_type(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + pos = luaL_opt_int(L, 2, n); + if (n <= 0) return 0; /* table is `empty' */ + aux_setn(L, 1, n-1); /* t.n = n-1 */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos<n; pos++) { + lua_rawgeti(L, 1, pos+1); + lua_rawseti(L, 1, pos); /* a[pos] = a[pos+1] */ + } + lua_pushnil(L); + lua_rawseti(L, 1, n); /* t[n] = nil */ + return 1; +} + + + +/* +** {====================================================== +** Quicksort +** (based on `Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +*/ + + +static void set2 (lua_State *L, int i, int j) { + lua_rawseti(L, 1, i); + lua_rawseti(L, 1, j); +} + +static int sort_comp (lua_State *L, int a, int b) { + /* WARNING: the caller (auxsort) must ensure stack space */ + if (!lua_isnoneornil(L, 2)) { /* function? */ + int res; + lua_pushvalue(L, 2); + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ + lua_rawcall(L, 2, 1); + res = lua_toboolean(L, -1); + lua_pop(L, 1); + return res; + } + else /* a < b? */ + return lua_lessthan(L, a, b); +} + +static void auxsort (lua_State *L, int l, int u) { + while (l < u) { /* for tail recursion */ + int i, j; + /* sort elements a[l], a[(l+u)/2] and a[u] */ + lua_rawgeti(L, 1, l); + lua_rawgeti(L, 1, u); + if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ + set2(L, l, u); /* swap a[l] - a[u] */ + else + lua_pop(L, 2); + if (u-l == 1) break; /* only 2 elements */ + i = (l+u)/2; + lua_rawgeti(L, 1, i); + lua_rawgeti(L, 1, l); + if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */ + set2(L, i, l); + else { + lua_pop(L, 1); /* remove a[l] */ + lua_rawgeti(L, 1, u); + if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */ + set2(L, i, u); + else + lua_pop(L, 2); + } + if (u-l == 2) break; /* only 3 elements */ + lua_rawgeti(L, 1, i); /* Pivot */ + lua_pushvalue(L, -1); + lua_rawgeti(L, 1, u-1); + set2(L, i, u-1); + /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ + i = l; j = u-1; + for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ + /* repeat ++i until a[i] >= P */ + while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i>u) lua_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j<l) lua_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + if (j<i) { + lua_pop(L, 3); /* pop pivot, a[i], a[j] */ + break; + } + set2(L, i, j); + } + lua_rawgeti(L, 1, u-1); + lua_rawgeti(L, 1, i); + set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */ + /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ + /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ + if (i-l < u-i) { + j=l; i=i-1; l=i+2; + } + else { + j=i+1; i=u; u=j-2; + } + auxsort(L, j, i); /* call recursively the smaller one */ + } /* repeat the routine for the larger one */ +} + +static int luaB_sort (lua_State *L) { + int n; + luaL_check_type(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + if (!lua_isnone(L, 2)) /* is there a 2nd argument? */ + luaL_check_type(L, 2, LUA_TFUNCTION); + lua_settop(L, 2); /* make sure there is two arguments */ + auxsort(L, 1, n); + return 0; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Coroutine library +** ======================================================= +*/ + + +static int luaB_resume (lua_State *L) { + lua_State *co = (lua_State *)lua_getfrombox(L, lua_upvalueindex(1)); + lua_settop(L, 0); + if (lua_resume(L, co) != 0) + lua_error(L, "error running co-routine"); + return lua_gettop(L); +} + + + +static int gc_coroutine (lua_State *L) { + lua_State *co = (lua_State *)lua_getfrombox(L, 1); + lua_closethread(L, co); + return 0; +} + + +static int luaB_coroutine (lua_State *L) { + lua_State *NL; + int ref; + int i; + int n = lua_gettop(L); + luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + NL = lua_newthread(L); + if (NL == NULL) lua_error(L, "unable to create new thread"); + /* move function and arguments from L to NL */ + for (i=0; i<n; i++) { + ref = lua_ref(L, 1); + lua_getref(NL, ref); + lua_insert(NL, 1); + lua_unref(L, ref); + } + lua_cobegin(NL, n-1); + lua_newpointerbox(L, NL); + lua_pushliteral(L, "Coroutine"); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + lua_pushcclosure(L, luaB_resume, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + +static const luaL_reg co_funcs[] = { + {"create", luaB_coroutine}, + {"yield", luaB_yield}, + {NULL, NULL} +}; + + +static void co_open (lua_State *L) { + luaL_opennamedlib(L, "co", co_funcs, 0); + /* create metatable for coroutines */ + lua_pushliteral(L, "Coroutine"); + lua_newtable(L); + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_coroutine); + lua_rawset(L, -3); + lua_rawset(L, LUA_REGISTRYINDEX); +} + +/* }====================================================== */ + + +static const luaL_reg tab_funcs[] = { + {"foreach", luaB_foreach}, + {"foreachi", luaB_foreachi}, + {"getn", luaB_getn}, + {"sort", luaB_sort}, + {"insert", luaB_tinsert}, + {"remove", luaB_tremove}, + {NULL, NULL} +}; + + +LUALIB_API int lua_tablibopen (lua_State *L) { + luaL_opennamedlib(L, "tab", tab_funcs, 0); + co_open(L); + return 0; +} +