diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-04-09 17:19:06 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-04-09 17:19:06 -0300 |
| commit | af4721f7a37834e5b5469f342caed0629932a4aa (patch) | |
| tree | 6077968abadf7864178714d31c6f7cdc69233877 | |
| parent | 018e50ad7f24aa8f8f4afe50d513964624c4ca35 (diff) | |
| download | lua-af4721f7a37834e5b5469f342caed0629932a4aa.tar.gz lua-af4721f7a37834e5b5469f342caed0629932a4aa.tar.bz2 lua-af4721f7a37834e5b5469f342caed0629932a4aa.zip | |
library with table manipulation functions
| -rw-r--r-- | ltablib.c | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/ltablib.c b/ltablib.c new file mode 100644 index 00000000..292a8f7a --- /dev/null +++ b/ltablib.c | |||
| @@ -0,0 +1,308 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: $ | ||
| 3 | ** Library for Table Manipulation | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | |||
| 8 | #include <stddef.h> | ||
| 9 | |||
| 10 | #include "lua.h" | ||
| 11 | |||
| 12 | #include "lauxlib.h" | ||
| 13 | #include "luadebug.h" | ||
| 14 | #include "lualib.h" | ||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | |||
| 19 | static int luaB_foreachi (lua_State *L) { | ||
| 20 | int n, i; | ||
| 21 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 22 | luaL_check_type(L, 2, LUA_TFUNCTION); | ||
| 23 | n = lua_getn(L, 1); | ||
| 24 | for (i=1; i<=n; i++) { | ||
| 25 | lua_pushvalue(L, 2); /* function */ | ||
| 26 | lua_pushnumber(L, i); /* 1st argument */ | ||
| 27 | lua_rawgeti(L, 1, i); /* 2nd argument */ | ||
| 28 | lua_rawcall(L, 2, 1); | ||
| 29 | if (!lua_isnil(L, -1)) | ||
| 30 | return 1; | ||
| 31 | lua_pop(L, 1); /* remove nil result */ | ||
| 32 | } | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | |||
| 37 | static int luaB_foreach (lua_State *L) { | ||
| 38 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 39 | luaL_check_type(L, 2, LUA_TFUNCTION); | ||
| 40 | lua_pushnil(L); /* first key */ | ||
| 41 | for (;;) { | ||
| 42 | if (lua_next(L, 1) == 0) | ||
| 43 | return 0; | ||
| 44 | lua_pushvalue(L, 2); /* function */ | ||
| 45 | lua_pushvalue(L, -3); /* key */ | ||
| 46 | lua_pushvalue(L, -3); /* value */ | ||
| 47 | lua_rawcall(L, 2, 1); | ||
| 48 | if (!lua_isnil(L, -1)) | ||
| 49 | return 1; | ||
| 50 | lua_pop(L, 2); /* remove value and result */ | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | |||
| 55 | static void aux_setn (lua_State *L, int t, int n) { | ||
| 56 | lua_pushliteral(L, "n"); | ||
| 57 | lua_pushnumber(L, n); | ||
| 58 | lua_rawset(L, t); | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 62 | static int luaB_getn (lua_State *L) { | ||
| 63 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 64 | lua_pushnumber(L, lua_getn(L, 1)); | ||
| 65 | return 1; | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | static int luaB_tinsert (lua_State *L) { | ||
| 70 | int v = lua_gettop(L); /* number of arguments */ | ||
| 71 | int n, pos; | ||
| 72 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 73 | n = lua_getn(L, 1); | ||
| 74 | if (v == 2) /* called with only 2 arguments */ | ||
| 75 | pos = n+1; | ||
| 76 | else { | ||
| 77 | v = 3; /* function may be called with more than 3 args */ | ||
| 78 | pos = luaL_check_int(L, 2); /* 2nd argument is the position */ | ||
| 79 | } | ||
| 80 | if (pos > n+1) n = pos-1; | ||
| 81 | aux_setn(L, 1, n+1); /* t.n = n+1 */ | ||
| 82 | for (; n>=pos; n--) { | ||
| 83 | lua_rawgeti(L, 1, n); | ||
| 84 | lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ | ||
| 85 | } | ||
| 86 | lua_pushvalue(L, v); | ||
| 87 | lua_rawseti(L, 1, pos); /* t[pos] = v */ | ||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | static int luaB_tremove (lua_State *L) { | ||
| 93 | int pos, n; | ||
| 94 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 95 | n = lua_getn(L, 1); | ||
| 96 | pos = luaL_opt_int(L, 2, n); | ||
| 97 | if (n <= 0) return 0; /* table is `empty' */ | ||
| 98 | aux_setn(L, 1, n-1); /* t.n = n-1 */ | ||
| 99 | lua_rawgeti(L, 1, pos); /* result = t[pos] */ | ||
| 100 | for ( ;pos<n; pos++) { | ||
| 101 | lua_rawgeti(L, 1, pos+1); | ||
| 102 | lua_rawseti(L, 1, pos); /* a[pos] = a[pos+1] */ | ||
| 103 | } | ||
| 104 | lua_pushnil(L); | ||
| 105 | lua_rawseti(L, 1, n); /* t[n] = nil */ | ||
| 106 | return 1; | ||
| 107 | } | ||
| 108 | |||
| 109 | |||
| 110 | |||
| 111 | /* | ||
| 112 | ** {====================================================== | ||
| 113 | ** Quicksort | ||
| 114 | ** (based on `Algorithms in MODULA-3', Robert Sedgewick; | ||
| 115 | ** Addison-Wesley, 1993.) | ||
| 116 | */ | ||
| 117 | |||
| 118 | |||
| 119 | static void set2 (lua_State *L, int i, int j) { | ||
| 120 | lua_rawseti(L, 1, i); | ||
| 121 | lua_rawseti(L, 1, j); | ||
| 122 | } | ||
| 123 | |||
| 124 | static int sort_comp (lua_State *L, int a, int b) { | ||
| 125 | /* WARNING: the caller (auxsort) must ensure stack space */ | ||
| 126 | if (!lua_isnoneornil(L, 2)) { /* function? */ | ||
| 127 | int res; | ||
| 128 | lua_pushvalue(L, 2); | ||
| 129 | lua_pushvalue(L, a-1); /* -1 to compensate function */ | ||
| 130 | lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ | ||
| 131 | lua_rawcall(L, 2, 1); | ||
| 132 | res = lua_toboolean(L, -1); | ||
| 133 | lua_pop(L, 1); | ||
| 134 | return res; | ||
| 135 | } | ||
| 136 | else /* a < b? */ | ||
| 137 | return lua_lessthan(L, a, b); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void auxsort (lua_State *L, int l, int u) { | ||
| 141 | while (l < u) { /* for tail recursion */ | ||
| 142 | int i, j; | ||
| 143 | /* sort elements a[l], a[(l+u)/2] and a[u] */ | ||
| 144 | lua_rawgeti(L, 1, l); | ||
| 145 | lua_rawgeti(L, 1, u); | ||
| 146 | if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ | ||
| 147 | set2(L, l, u); /* swap a[l] - a[u] */ | ||
| 148 | else | ||
| 149 | lua_pop(L, 2); | ||
| 150 | if (u-l == 1) break; /* only 2 elements */ | ||
| 151 | i = (l+u)/2; | ||
| 152 | lua_rawgeti(L, 1, i); | ||
| 153 | lua_rawgeti(L, 1, l); | ||
| 154 | if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */ | ||
| 155 | set2(L, i, l); | ||
| 156 | else { | ||
| 157 | lua_pop(L, 1); /* remove a[l] */ | ||
| 158 | lua_rawgeti(L, 1, u); | ||
| 159 | if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */ | ||
| 160 | set2(L, i, u); | ||
| 161 | else | ||
| 162 | lua_pop(L, 2); | ||
| 163 | } | ||
| 164 | if (u-l == 2) break; /* only 3 elements */ | ||
| 165 | lua_rawgeti(L, 1, i); /* Pivot */ | ||
| 166 | lua_pushvalue(L, -1); | ||
| 167 | lua_rawgeti(L, 1, u-1); | ||
| 168 | set2(L, i, u-1); | ||
| 169 | /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ | ||
| 170 | i = l; j = u-1; | ||
| 171 | for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ | ||
| 172 | /* repeat ++i until a[i] >= P */ | ||
| 173 | while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { | ||
| 174 | if (i>u) lua_error(L, "invalid order function for sorting"); | ||
| 175 | lua_pop(L, 1); /* remove a[i] */ | ||
| 176 | } | ||
| 177 | /* repeat --j until a[j] <= P */ | ||
| 178 | while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { | ||
| 179 | if (j<l) lua_error(L, "invalid order function for sorting"); | ||
| 180 | lua_pop(L, 1); /* remove a[j] */ | ||
| 181 | } | ||
| 182 | if (j<i) { | ||
| 183 | lua_pop(L, 3); /* pop pivot, a[i], a[j] */ | ||
| 184 | break; | ||
| 185 | } | ||
| 186 | set2(L, i, j); | ||
| 187 | } | ||
| 188 | lua_rawgeti(L, 1, u-1); | ||
| 189 | lua_rawgeti(L, 1, i); | ||
| 190 | set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */ | ||
| 191 | /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ | ||
| 192 | /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ | ||
| 193 | if (i-l < u-i) { | ||
| 194 | j=l; i=i-1; l=i+2; | ||
| 195 | } | ||
| 196 | else { | ||
| 197 | j=i+1; i=u; u=j-2; | ||
| 198 | } | ||
| 199 | auxsort(L, j, i); /* call recursively the smaller one */ | ||
| 200 | } /* repeat the routine for the larger one */ | ||
| 201 | } | ||
| 202 | |||
| 203 | static int luaB_sort (lua_State *L) { | ||
| 204 | int n; | ||
| 205 | luaL_check_type(L, 1, LUA_TTABLE); | ||
| 206 | n = lua_getn(L, 1); | ||
| 207 | if (!lua_isnone(L, 2)) /* is there a 2nd argument? */ | ||
| 208 | luaL_check_type(L, 2, LUA_TFUNCTION); | ||
| 209 | lua_settop(L, 2); /* make sure there is two arguments */ | ||
| 210 | auxsort(L, 1, n); | ||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | /* }====================================================== */ | ||
| 215 | |||
| 216 | |||
| 217 | /* | ||
| 218 | ** {====================================================== | ||
| 219 | ** Coroutine library | ||
| 220 | ** ======================================================= | ||
| 221 | */ | ||
| 222 | |||
| 223 | |||
| 224 | static int luaB_resume (lua_State *L) { | ||
| 225 | lua_State *co = (lua_State *)lua_getfrombox(L, lua_upvalueindex(1)); | ||
| 226 | lua_settop(L, 0); | ||
| 227 | if (lua_resume(L, co) != 0) | ||
| 228 | lua_error(L, "error running co-routine"); | ||
| 229 | return lua_gettop(L); | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | |||
| 234 | static int gc_coroutine (lua_State *L) { | ||
| 235 | lua_State *co = (lua_State *)lua_getfrombox(L, 1); | ||
| 236 | lua_closethread(L, co); | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | |||
| 241 | static int luaB_coroutine (lua_State *L) { | ||
| 242 | lua_State *NL; | ||
| 243 | int ref; | ||
| 244 | int i; | ||
| 245 | int n = lua_gettop(L); | ||
| 246 | luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, | ||
| 247 | "Lua function expected"); | ||
| 248 | NL = lua_newthread(L); | ||
| 249 | if (NL == NULL) lua_error(L, "unable to create new thread"); | ||
| 250 | /* move function and arguments from L to NL */ | ||
| 251 | for (i=0; i<n; i++) { | ||
| 252 | ref = lua_ref(L, 1); | ||
| 253 | lua_getref(NL, ref); | ||
| 254 | lua_insert(NL, 1); | ||
| 255 | lua_unref(L, ref); | ||
| 256 | } | ||
| 257 | lua_cobegin(NL, n-1); | ||
| 258 | lua_newpointerbox(L, NL); | ||
| 259 | lua_pushliteral(L, "Coroutine"); | ||
| 260 | lua_rawget(L, LUA_REGISTRYINDEX); | ||
| 261 | lua_setmetatable(L, -2); | ||
| 262 | lua_pushcclosure(L, luaB_resume, 1); | ||
| 263 | return 1; | ||
| 264 | } | ||
| 265 | |||
| 266 | |||
| 267 | static int luaB_yield (lua_State *L) { | ||
| 268 | return lua_yield(L, lua_gettop(L)); | ||
| 269 | } | ||
| 270 | |||
| 271 | static const luaL_reg co_funcs[] = { | ||
| 272 | {"create", luaB_coroutine}, | ||
| 273 | {"yield", luaB_yield}, | ||
| 274 | {NULL, NULL} | ||
| 275 | }; | ||
| 276 | |||
| 277 | |||
| 278 | static void co_open (lua_State *L) { | ||
| 279 | luaL_opennamedlib(L, "co", co_funcs, 0); | ||
| 280 | /* create metatable for coroutines */ | ||
| 281 | lua_pushliteral(L, "Coroutine"); | ||
| 282 | lua_newtable(L); | ||
| 283 | lua_pushliteral(L, "__gc"); | ||
| 284 | lua_pushcfunction(L, gc_coroutine); | ||
| 285 | lua_rawset(L, -3); | ||
| 286 | lua_rawset(L, LUA_REGISTRYINDEX); | ||
| 287 | } | ||
| 288 | |||
| 289 | /* }====================================================== */ | ||
| 290 | |||
| 291 | |||
| 292 | static const luaL_reg tab_funcs[] = { | ||
| 293 | {"foreach", luaB_foreach}, | ||
| 294 | {"foreachi", luaB_foreachi}, | ||
| 295 | {"getn", luaB_getn}, | ||
| 296 | {"sort", luaB_sort}, | ||
| 297 | {"insert", luaB_tinsert}, | ||
| 298 | {"remove", luaB_tremove}, | ||
| 299 | {NULL, NULL} | ||
| 300 | }; | ||
| 301 | |||
| 302 | |||
| 303 | LUALIB_API int lua_tablibopen (lua_State *L) { | ||
| 304 | luaL_opennamedlib(L, "tab", tab_funcs, 0); | ||
| 305 | co_open(L); | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | |||
