#include "table.hpp" #include "source.hpp" LuaDefine(table_getregistry, "f") { LuaArg key; LuaRet result; LuaStack LS(L, key, result); LS.rawget(result, LuaRegistry, key); return LS.result(); } LuaDefine(table_equal, "c") { LuaArg t1, t2; LuaRet eql; LuaStack LS(L, t1, t2, eql); LS.checktable(t1); LS.checktable(t2); lua_pushnil(L); int total1 = 0; while (lua_next(L, t1.index()) != 0) { lua_pushvalue(L, -2); // k v1 k lua_rawget(L, t2.index()); // k v1 v2 if (!lua_rawequal(L, -1, -2)) { LS.set(eql, false); return LS.result(); } lua_pop(L, 2); total1 += 1; } int total2 = 0; lua_pushnil(L); while (lua_next(L, t2.index()) != 0) { lua_pop(L, 1); total2 += 1; } LS.set(eql, total1 == total2); return LS.result(); } LuaDefine(table_findremove, "c") { luaL_checktype(L, -2, LUA_TTABLE); int src = 1; int dst = 1; while (true) { lua_pushinteger(L, src); lua_rawget(L, -3); if (lua_rawequal(L, -1, -2)) { src++; lua_pop(L, 1); } else if (lua_isnil(L, -1)) { lua_pop(L, 1); int removed = src - dst; while (src > dst) { lua_pushinteger(L, dst); lua_pushnil(L); lua_rawset(L, -4); dst++; } lua_pop(L, 2); lua_pushinteger(L, removed); return 1; } else { if (src > dst) { lua_pushinteger(L, dst); lua_insert(L, lua_gettop(L) - 1); lua_rawset(L, -4); } else { lua_pop(L, 1); } src++; dst++; } } } LuaDefine(table_push, "c") { luaL_checktype(L, -2, LUA_TTABLE); int len = lua_rawlen(L, -2); lua_pushinteger(L, len+1); lua_pushvalue(L, -2); lua_rawset(L, -4); lua_pop(L, 2); return 0; } LuaDefine(table_find, "c") { luaL_checktype(L, -2, LUA_TTABLE); for (int i = 1; ; i++) { lua_pushinteger(L, i); lua_rawget(L, -3); if (lua_rawequal(L, -1, -2)) { lua_pop(L, 3); lua_pushinteger(L, i); return 1; } else if (lua_isnil(L, -1)) { lua_pop(L, 3); lua_pushnil(L); return 1; } else { lua_pop(L, 1); } } } LuaDefine(table_empty, "c") { luaL_checktype(L, -1, LUA_TTABLE); lua_pushnil(L); if (lua_next(L, -2) != 0) { lua_pop(L, 3); lua_pushboolean(L, 0); return 1; } else { lua_pop(L, 1); lua_pushboolean(L, 1); return 1; } } LuaDefine(table_count, "c") { luaL_checktype(L, -1, LUA_TTABLE); int total = lua_nkeys(L, -1); lua_pushinteger(L, total); return 1; } LuaDefine(table_clear, "c") { LuaArg tab; LuaStack LS(L, tab); LS.cleartable(tab); return LS.result(); } ///////////////////////////////////////////////////////////// // // Queue operators. // ///////////////////////////////////////////////////////////// #define QUEUE_POP 1 #define QUEUE_FILL 2 #define QUEUE_MAX 3 #define QUEUE_BASE 4 LuaDefine(queue_create, "c") { LuaRet queue; LuaStack LS(L, queue); const int imax = 8; LS.createtable(queue, QUEUE_BASE + imax - 1, 0); LS.rawseti(queue, QUEUE_POP, 0); LS.rawseti(queue, QUEUE_FILL, 0); LS.rawseti(queue, QUEUE_MAX, imax); for (int i = 0; i < imax; i++) { LS.rawseti(queue, QUEUE_BASE + i, 0); } return LS.result(); } LuaDefine(queue_push, "c") { LuaArg queue, elt; LuaVar qpop, qfill, qmax, t; LuaStack LS(L, queue, elt, qpop, qfill, qmax, t); LS.checktable(queue); LS.rawgeti(qpop, queue, QUEUE_POP); LS.rawgeti(qfill, queue, QUEUE_FILL); LS.rawgeti(qmax, queue, QUEUE_MAX); int pop = LS.ckint(qpop); int fill = LS.ckint(qfill); int max = LS.ckint(qmax); if (fill == max) { int overflow = (pop + fill) - max; if (overflow < 0) overflow = 0; for (int i = 0; i < overflow; i++) { lua_rawgeti(L, queue.index(), QUEUE_BASE + i); lua_rawseti(L, queue.index(), QUEUE_BASE + i + max); lua_pushinteger(L, 0); lua_rawseti(L, queue.index(), QUEUE_BASE + i); } for (int i = overflow; i < max; i++) { lua_pushinteger(L, 0); lua_rawseti(L, queue.index(), QUEUE_BASE + i + max); } max *= 2; LS.rawseti(queue, QUEUE_MAX, max); } int target = pop + fill; if (target >= max) target -= max; LS.rawseti(queue, QUEUE_BASE + target, elt); LS.rawseti(queue, QUEUE_FILL, fill + 1); return LS.result(); } LuaDefine(queue_pop, "c") { LuaArg queue; LuaVar qpop, qfill, qmax, t; LuaRet result; LuaStack LS(L, queue, qpop, qfill, qmax, result, t); LS.checktable(queue); LS.rawgeti(qpop, queue, QUEUE_POP); LS.rawgeti(qfill, queue, QUEUE_FILL); LS.rawgeti(qmax, queue, QUEUE_MAX); int fill = LS.ckint(qfill); if (fill <= 0) { LS.set(result, LuaNil); return LS.result(); } int pop = LS.ckint(qpop); int max = LS.ckint(qmax); LS.rawgeti(result, queue, QUEUE_BASE + pop); LS.rawseti(queue, QUEUE_BASE + pop, 0); int next = pop + 1; if (next == max) next = 0; LS.rawseti(queue, QUEUE_POP, next); LS.rawseti(queue, QUEUE_FILL, fill - 1); return LS.result(); } LuaDefine(queue_size, "c") { LuaArg queue; LuaRet size; LuaStack LS(L, queue, size); LS.checktable(queue); LS.rawget(size, queue, QUEUE_FILL); LS.checknumber(size); return LS.result(); } LuaDefine(queue_nth, "c") { LuaArg queue, nn; LuaVar qpop, qfill, qmax; LuaRet elt; LuaStack LS(L, queue, nn, qpop, qfill, qmax, elt); LS.checktable(queue); int n = LS.ckint(nn) - 1; LS.rawgeti(qfill, queue, QUEUE_FILL); int fill = LS.ckint(qfill); if ((n < 0) || (n >= fill)) { LS.set(elt, LuaNil); return LS.result(); } LS.rawgeti(qpop, queue, QUEUE_POP); LS.rawgeti(qmax, queue, QUEUE_MAX); int pop = LS.ckint(qpop); int max = LS.ckint(qmax); int index = pop + n; if (index > max) index -= max; LS.rawgeti(elt, queue, QUEUE_BASE + index); return LS.result(); } ///////////////////////////////////////////////////////////// // // table_getpairs // // Given a table, return all the pairs in the table as a sequence. // The resulting sequence contains a 1 in the first position, // followed by the pairs, like so: // // sortedpairs({a=1,b=2,c=3}) => {1,"a",1,"b",2,"c",3} // // Note that this function is not directly exposed to lua. // It's exposed only through the 'sortedpairs' iterator. // ///////////////////////////////////////////////////////////// static void pushkey (lua_State *L, int tab, int i) { lua_rawgeti(L, tab, i*2); } static void push2keys (lua_State *L, int tab, int i, int j) { lua_rawgeti(L, tab, i*2); lua_rawgeti(L, tab, j*2); } static void pop2keys (lua_State *L, int tab, int i, int j) { lua_rawseti(L, tab, i*2); lua_rawseti(L, tab, j*2); } static void swap2values (lua_State *L, int tab, int i, int j) { lua_rawgeti(L, tab, i*2+1); lua_rawgeti(L, tab, j*2+1); lua_rawseti(L, tab, i*2+1); lua_rawseti(L, tab, j*2+1); } static void auxsort (lua_State *L, int tab, int l, int u) { while (l < u) { /* for tail recursion */ int i, j; /* sort elements a[l], a[(l+u)/2] and a[u] */ push2keys(L, tab, l, u); if (lua_genlt(L, -1, -2)) { pop2keys(L, tab, l, u); swap2values(L, tab, l, u); } else { lua_pop(L, 2); } if (u - l == 1) break; /* only 2 elements */ i = (l + u) / 2; push2keys(L, tab, i, l); if (lua_genlt(L, -2, -1)) { pop2keys(L, tab, i, l); swap2values(L, tab, i, l); } else { lua_pop(L, 1); /* remove a[l] */ pushkey(L, tab, u); if (lua_genlt(L, -1, -2)) { pop2keys(L, tab, i, u); swap2values(L, tab, i, u); } else { lua_pop(L, 2); } } if (u - l == 2) break; /* only 3 elements */ /* put the pivot value on top of the stack and keep it there */ pushkey(L, tab, i); /* move the pivot from i to u-1 */ lua_pushvalue(L, -1); pushkey(L, tab, u-1); pop2keys(L, tab, i, u-1); swap2values(L, tab, 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 (pushkey(L, tab, ++i), lua_genlt(L, -1, -2)) { if (i >= u) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* repeat --j until a[j] <= P */ while (pushkey(L, tab, --j), lua_genlt(L, -3, -1)) { if (j <= l) luaL_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; } pop2keys(L, tab, i, j); swap2values(L, tab, i, j); } push2keys(L, tab, u-1, i); pop2keys(L, tab, u-1, i); swap2values(L, tab, u-1, 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, tab, j, i); /* call recursively the smaller one */ } /* repeat the routine for the larger one */ } static int table_getpairs(lua_State *L, bool sort, bool *unsortable) { lua_checkstack(L, 40); LuaArg tab; LuaVar key, value; LuaRet pairs; LuaStack LS(L, tab, key, value, pairs); if (unsortable != nullptr) { *unsortable = false; } LS.checktable(tab); // Count the total number of pairs. // TODO: add lua_npairs to make this faster. lua_pushnil(L); int total = 0; while (lua_next(L, tab.index()) != 0) { int ktype = lua_type(L, -2); if (ktype == LUA_TNUMBER || ktype == LUA_TSTRING || ktype == LUA_TBOOLEAN) { total += 1; } lua_pop(L, 1); } // Create the table, store the initial 1. LS.createtable(pairs, total * 2 + 1, 0); LS.rawseti(pairs, 1, 1); // Transfer the pairs into the sequence. lua_pushnil(L); int offset = 2; while (lua_next(L, tab.index()) != 0) { int ktype = lua_type(L, -2); if (ktype == LUA_TNUMBER || ktype == LUA_TSTRING || ktype == LUA_TBOOLEAN) { lua_pushvalue(L, -2); // K V K lua_rawseti(L, pairs.index(), offset++); lua_rawseti(L, pairs.index(), offset++); } else { if (unsortable != nullptr) { *unsortable = true; } lua_pop(L, 1); } } if (sort) { auxsort(L, pairs.index(), 1, total); } return LS.result(); } ///////////////////////////////////////////////////////////// // // Given a sortedpairs vector, return the (key, value) pairs // one by one. The first element of the vector is used as a // counter to keep track of our position. // ///////////////////////////////////////////////////////////// LuaDefine(table_nextsortedpair, "c") { if (lua_gettop(L) < 2) { luaL_error(L, "Not enough arguments to nextpair"); } luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 1); lua_Integer i = luaL_checkinteger(L, -1); lua_pop(L, 1); lua_pushinteger(L, i+1); lua_rawseti(L, 1, 1); lua_rawgeti(L, 1, i*2); if (lua_isnil(L, -1)) { return 1; } else { lua_rawgeti(L, 1, i*2+1); return 2; } } LuaDefine(table_sortedpairs, "c") { LuaArg tab; LuaRet closure, rtab, key; LuaStack LS(L, tab, closure, rtab, key); lua_pushvalue(L, tab.index()); bool unsortable; table_getpairs(L, true, &unsortable); if (unsortable) { luaL_error(L, "Cannot iterate over a table with unsortable keys"); } lua_replace(L, rtab.index()); LS.set(closure, table_nextsortedpair); LS.set(key, LuaNil); return LS.result(); } LuaDefine(table_genlt, "f") { LuaArg o1,o2; LuaRet lt; LuaStack LS(L, o1, o2, lt); int ltf = lua_genlt(L, o1.index(), o2.index()); LS.set(lt, ltf ? true:false); return LS.result(); }