mirror of https://github.com/lua/lua.git
Roberto Ierusalimschy
23 years ago
1 changed files with 308 additions and 0 deletions
@ -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; |
||||
|
} |
||||
|
|
Loading…
Reference in new issue