18e3e3a7aSWarner Losh /* 20495ed39SKyle Evans ** $Id: ltablib.c $ 38e3e3a7aSWarner Losh ** Library for Table Manipulation 48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 58e3e3a7aSWarner Losh */ 68e3e3a7aSWarner Losh 78e3e3a7aSWarner Losh #define ltablib_c 88e3e3a7aSWarner Losh #define LUA_LIB 98e3e3a7aSWarner Losh 108e3e3a7aSWarner Losh #include "lprefix.h" 118e3e3a7aSWarner Losh 128e3e3a7aSWarner Losh 138e3e3a7aSWarner Losh #include <limits.h> 148e3e3a7aSWarner Losh #include <stddef.h> 158e3e3a7aSWarner Losh #include <string.h> 168e3e3a7aSWarner Losh 178e3e3a7aSWarner Losh #include "lua.h" 188e3e3a7aSWarner Losh 198e3e3a7aSWarner Losh #include "lauxlib.h" 208e3e3a7aSWarner Losh #include "lualib.h" 218e3e3a7aSWarner Losh 228e3e3a7aSWarner Losh 238e3e3a7aSWarner Losh /* 248e3e3a7aSWarner Losh ** Operations that an object must define to mimic a table 258e3e3a7aSWarner Losh ** (some functions only need some of them) 268e3e3a7aSWarner Losh */ 278e3e3a7aSWarner Losh #define TAB_R 1 /* read */ 288e3e3a7aSWarner Losh #define TAB_W 2 /* write */ 298e3e3a7aSWarner Losh #define TAB_L 4 /* length */ 308e3e3a7aSWarner Losh #define TAB_RW (TAB_R | TAB_W) /* read/write */ 318e3e3a7aSWarner Losh 328e3e3a7aSWarner Losh 338e3e3a7aSWarner Losh #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) 348e3e3a7aSWarner Losh 358e3e3a7aSWarner Losh 368e3e3a7aSWarner Losh static int checkfield (lua_State *L, const char *key, int n) { 378e3e3a7aSWarner Losh lua_pushstring(L, key); 388e3e3a7aSWarner Losh return (lua_rawget(L, -n) != LUA_TNIL); 398e3e3a7aSWarner Losh } 408e3e3a7aSWarner Losh 418e3e3a7aSWarner Losh 428e3e3a7aSWarner Losh /* 438e3e3a7aSWarner Losh ** Check that 'arg' either is a table or can behave like one (that is, 448e3e3a7aSWarner Losh ** has a metatable with the required metamethods) 458e3e3a7aSWarner Losh */ 468e3e3a7aSWarner Losh static void checktab (lua_State *L, int arg, int what) { 478e3e3a7aSWarner Losh if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ 488e3e3a7aSWarner Losh int n = 1; /* number of elements to pop */ 498e3e3a7aSWarner Losh if (lua_getmetatable(L, arg) && /* must have metatable */ 508e3e3a7aSWarner Losh (!(what & TAB_R) || checkfield(L, "__index", ++n)) && 518e3e3a7aSWarner Losh (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && 528e3e3a7aSWarner Losh (!(what & TAB_L) || checkfield(L, "__len", ++n))) { 538e3e3a7aSWarner Losh lua_pop(L, n); /* pop metatable and tested metamethods */ 548e3e3a7aSWarner Losh } 558e3e3a7aSWarner Losh else 568e3e3a7aSWarner Losh luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ 578e3e3a7aSWarner Losh } 588e3e3a7aSWarner Losh } 598e3e3a7aSWarner Losh 608e3e3a7aSWarner Losh 618e3e3a7aSWarner Losh static int tinsert (lua_State *L) { 628e3e3a7aSWarner Losh lua_Integer pos; /* where to insert new element */ 63*8c784bb8SWarner Losh lua_Integer e = aux_getn(L, 1, TAB_RW); 64*8c784bb8SWarner Losh e = luaL_intop(+, e, 1); /* first empty element */ 658e3e3a7aSWarner Losh switch (lua_gettop(L)) { 668e3e3a7aSWarner Losh case 2: { /* called with only 2 arguments */ 678e3e3a7aSWarner Losh pos = e; /* insert new element at the end */ 688e3e3a7aSWarner Losh break; 698e3e3a7aSWarner Losh } 708e3e3a7aSWarner Losh case 3: { 718e3e3a7aSWarner Losh lua_Integer i; 728e3e3a7aSWarner Losh pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ 730495ed39SKyle Evans /* check whether 'pos' is in [1, e] */ 740495ed39SKyle Evans luaL_argcheck(L, (lua_Unsigned)pos - 1u < (lua_Unsigned)e, 2, 750495ed39SKyle Evans "position out of bounds"); 768e3e3a7aSWarner Losh for (i = e; i > pos; i--) { /* move up elements */ 778e3e3a7aSWarner Losh lua_geti(L, 1, i - 1); 788e3e3a7aSWarner Losh lua_seti(L, 1, i); /* t[i] = t[i - 1] */ 798e3e3a7aSWarner Losh } 808e3e3a7aSWarner Losh break; 818e3e3a7aSWarner Losh } 828e3e3a7aSWarner Losh default: { 838e3e3a7aSWarner Losh return luaL_error(L, "wrong number of arguments to 'insert'"); 848e3e3a7aSWarner Losh } 858e3e3a7aSWarner Losh } 868e3e3a7aSWarner Losh lua_seti(L, 1, pos); /* t[pos] = v */ 878e3e3a7aSWarner Losh return 0; 888e3e3a7aSWarner Losh } 898e3e3a7aSWarner Losh 908e3e3a7aSWarner Losh 918e3e3a7aSWarner Losh static int tremove (lua_State *L) { 928e3e3a7aSWarner Losh lua_Integer size = aux_getn(L, 1, TAB_RW); 938e3e3a7aSWarner Losh lua_Integer pos = luaL_optinteger(L, 2, size); 948e3e3a7aSWarner Losh if (pos != size) /* validate 'pos' if given */ 950495ed39SKyle Evans /* check whether 'pos' is in [1, size + 1] */ 960495ed39SKyle Evans luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1, 970495ed39SKyle Evans "position out of bounds"); 988e3e3a7aSWarner Losh lua_geti(L, 1, pos); /* result = t[pos] */ 998e3e3a7aSWarner Losh for ( ; pos < size; pos++) { 1008e3e3a7aSWarner Losh lua_geti(L, 1, pos + 1); 1018e3e3a7aSWarner Losh lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ 1028e3e3a7aSWarner Losh } 1038e3e3a7aSWarner Losh lua_pushnil(L); 1040495ed39SKyle Evans lua_seti(L, 1, pos); /* remove entry t[pos] */ 1058e3e3a7aSWarner Losh return 1; 1068e3e3a7aSWarner Losh } 1078e3e3a7aSWarner Losh 1088e3e3a7aSWarner Losh 1098e3e3a7aSWarner Losh /* 1108e3e3a7aSWarner Losh ** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever 1118e3e3a7aSWarner Losh ** possible, copy in increasing order, which is better for rehashing. 1128e3e3a7aSWarner Losh ** "possible" means destination after original range, or smaller 1138e3e3a7aSWarner Losh ** than origin, or copying to another table. 1148e3e3a7aSWarner Losh */ 1158e3e3a7aSWarner Losh static int tmove (lua_State *L) { 1168e3e3a7aSWarner Losh lua_Integer f = luaL_checkinteger(L, 2); 1178e3e3a7aSWarner Losh lua_Integer e = luaL_checkinteger(L, 3); 1188e3e3a7aSWarner Losh lua_Integer t = luaL_checkinteger(L, 4); 1198e3e3a7aSWarner Losh int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ 1208e3e3a7aSWarner Losh checktab(L, 1, TAB_R); 1218e3e3a7aSWarner Losh checktab(L, tt, TAB_W); 1228e3e3a7aSWarner Losh if (e >= f) { /* otherwise, nothing to move */ 1238e3e3a7aSWarner Losh lua_Integer n, i; 1248e3e3a7aSWarner Losh luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, 1258e3e3a7aSWarner Losh "too many elements to move"); 1268e3e3a7aSWarner Losh n = e - f + 1; /* number of elements to move */ 1278e3e3a7aSWarner Losh luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, 1288e3e3a7aSWarner Losh "destination wrap around"); 1298e3e3a7aSWarner Losh if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { 1308e3e3a7aSWarner Losh for (i = 0; i < n; i++) { 1318e3e3a7aSWarner Losh lua_geti(L, 1, f + i); 1328e3e3a7aSWarner Losh lua_seti(L, tt, t + i); 1338e3e3a7aSWarner Losh } 1348e3e3a7aSWarner Losh } 1358e3e3a7aSWarner Losh else { 1368e3e3a7aSWarner Losh for (i = n - 1; i >= 0; i--) { 1378e3e3a7aSWarner Losh lua_geti(L, 1, f + i); 1388e3e3a7aSWarner Losh lua_seti(L, tt, t + i); 1398e3e3a7aSWarner Losh } 1408e3e3a7aSWarner Losh } 1418e3e3a7aSWarner Losh } 1428e3e3a7aSWarner Losh lua_pushvalue(L, tt); /* return destination table */ 1438e3e3a7aSWarner Losh return 1; 1448e3e3a7aSWarner Losh } 1458e3e3a7aSWarner Losh 1468e3e3a7aSWarner Losh 1478e3e3a7aSWarner Losh static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { 1488e3e3a7aSWarner Losh lua_geti(L, 1, i); 149*8c784bb8SWarner Losh if (l_unlikely(!lua_isstring(L, -1))) 150*8c784bb8SWarner Losh luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", 151*8c784bb8SWarner Losh luaL_typename(L, -1), (LUAI_UACINT)i); 1528e3e3a7aSWarner Losh luaL_addvalue(b); 1538e3e3a7aSWarner Losh } 1548e3e3a7aSWarner Losh 1558e3e3a7aSWarner Losh 1568e3e3a7aSWarner Losh static int tconcat (lua_State *L) { 1578e3e3a7aSWarner Losh luaL_Buffer b; 1588e3e3a7aSWarner Losh lua_Integer last = aux_getn(L, 1, TAB_R); 1598e3e3a7aSWarner Losh size_t lsep; 1608e3e3a7aSWarner Losh const char *sep = luaL_optlstring(L, 2, "", &lsep); 1618e3e3a7aSWarner Losh lua_Integer i = luaL_optinteger(L, 3, 1); 1628e3e3a7aSWarner Losh last = luaL_optinteger(L, 4, last); 1638e3e3a7aSWarner Losh luaL_buffinit(L, &b); 1648e3e3a7aSWarner Losh for (; i < last; i++) { 1658e3e3a7aSWarner Losh addfield(L, &b, i); 1668e3e3a7aSWarner Losh luaL_addlstring(&b, sep, lsep); 1678e3e3a7aSWarner Losh } 1688e3e3a7aSWarner Losh if (i == last) /* add last value (if interval was not empty) */ 1698e3e3a7aSWarner Losh addfield(L, &b, i); 1708e3e3a7aSWarner Losh luaL_pushresult(&b); 1718e3e3a7aSWarner Losh return 1; 1728e3e3a7aSWarner Losh } 1738e3e3a7aSWarner Losh 1748e3e3a7aSWarner Losh 1758e3e3a7aSWarner Losh /* 1768e3e3a7aSWarner Losh ** {====================================================== 1778e3e3a7aSWarner Losh ** Pack/unpack 1788e3e3a7aSWarner Losh ** ======================================================= 1798e3e3a7aSWarner Losh */ 1808e3e3a7aSWarner Losh 1810495ed39SKyle Evans static int tpack (lua_State *L) { 1828e3e3a7aSWarner Losh int i; 1838e3e3a7aSWarner Losh int n = lua_gettop(L); /* number of elements to pack */ 1848e3e3a7aSWarner Losh lua_createtable(L, n, 1); /* create result table */ 1858e3e3a7aSWarner Losh lua_insert(L, 1); /* put it at index 1 */ 1868e3e3a7aSWarner Losh for (i = n; i >= 1; i--) /* assign elements */ 1878e3e3a7aSWarner Losh lua_seti(L, 1, i); 1888e3e3a7aSWarner Losh lua_pushinteger(L, n); 1898e3e3a7aSWarner Losh lua_setfield(L, 1, "n"); /* t.n = number of elements */ 1908e3e3a7aSWarner Losh return 1; /* return table */ 1918e3e3a7aSWarner Losh } 1928e3e3a7aSWarner Losh 1938e3e3a7aSWarner Losh 1940495ed39SKyle Evans static int tunpack (lua_State *L) { 1958e3e3a7aSWarner Losh lua_Unsigned n; 1968e3e3a7aSWarner Losh lua_Integer i = luaL_optinteger(L, 2, 1); 1978e3e3a7aSWarner Losh lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); 1988e3e3a7aSWarner Losh if (i > e) return 0; /* empty range */ 1998e3e3a7aSWarner Losh n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ 200*8c784bb8SWarner Losh if (l_unlikely(n >= (unsigned int)INT_MAX || 201*8c784bb8SWarner Losh !lua_checkstack(L, (int)(++n)))) 2028e3e3a7aSWarner Losh return luaL_error(L, "too many results to unpack"); 2038e3e3a7aSWarner Losh for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ 2048e3e3a7aSWarner Losh lua_geti(L, 1, i); 2058e3e3a7aSWarner Losh } 2068e3e3a7aSWarner Losh lua_geti(L, 1, e); /* push last element */ 2078e3e3a7aSWarner Losh return (int)n; 2088e3e3a7aSWarner Losh } 2098e3e3a7aSWarner Losh 2108e3e3a7aSWarner Losh /* }====================================================== */ 2118e3e3a7aSWarner Losh 2128e3e3a7aSWarner Losh 2138e3e3a7aSWarner Losh 2148e3e3a7aSWarner Losh /* 2158e3e3a7aSWarner Losh ** {====================================================== 2168e3e3a7aSWarner Losh ** Quicksort 2178e3e3a7aSWarner Losh ** (based on 'Algorithms in MODULA-3', Robert Sedgewick; 2188e3e3a7aSWarner Losh ** Addison-Wesley, 1993.) 2198e3e3a7aSWarner Losh ** ======================================================= 2208e3e3a7aSWarner Losh */ 2218e3e3a7aSWarner Losh 2228e3e3a7aSWarner Losh 2238e3e3a7aSWarner Losh /* type for array indices */ 2248e3e3a7aSWarner Losh typedef unsigned int IdxT; 2258e3e3a7aSWarner Losh 2268e3e3a7aSWarner Losh 2278e3e3a7aSWarner Losh /* 2288e3e3a7aSWarner Losh ** Produce a "random" 'unsigned int' to randomize pivot choice. This 2298e3e3a7aSWarner Losh ** macro is used only when 'sort' detects a big imbalance in the result 2308e3e3a7aSWarner Losh ** of a partition. (If you don't want/need this "randomness", ~0 is a 2318e3e3a7aSWarner Losh ** good choice.) 2328e3e3a7aSWarner Losh */ 2338e3e3a7aSWarner Losh #if !defined(l_randomizePivot) /* { */ 2348e3e3a7aSWarner Losh 2358e3e3a7aSWarner Losh #include <time.h> 2368e3e3a7aSWarner Losh 2378e3e3a7aSWarner Losh /* size of 'e' measured in number of 'unsigned int's */ 2388e3e3a7aSWarner Losh #define sof(e) (sizeof(e) / sizeof(unsigned int)) 2398e3e3a7aSWarner Losh 2408e3e3a7aSWarner Losh /* 2418e3e3a7aSWarner Losh ** Use 'time' and 'clock' as sources of "randomness". Because we don't 2428e3e3a7aSWarner Losh ** know the types 'clock_t' and 'time_t', we cannot cast them to 2438e3e3a7aSWarner Losh ** anything without risking overflows. A safe way to use their values 2448e3e3a7aSWarner Losh ** is to copy them to an array of a known type and use the array values. 2458e3e3a7aSWarner Losh */ 2468e3e3a7aSWarner Losh static unsigned int l_randomizePivot (void) { 2478e3e3a7aSWarner Losh clock_t c = clock(); 2488e3e3a7aSWarner Losh time_t t = time(NULL); 2498e3e3a7aSWarner Losh unsigned int buff[sof(c) + sof(t)]; 2508e3e3a7aSWarner Losh unsigned int i, rnd = 0; 2518e3e3a7aSWarner Losh memcpy(buff, &c, sof(c) * sizeof(unsigned int)); 2528e3e3a7aSWarner Losh memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); 2538e3e3a7aSWarner Losh for (i = 0; i < sof(buff); i++) 2548e3e3a7aSWarner Losh rnd += buff[i]; 2558e3e3a7aSWarner Losh return rnd; 2568e3e3a7aSWarner Losh } 2578e3e3a7aSWarner Losh 2588e3e3a7aSWarner Losh #endif /* } */ 2598e3e3a7aSWarner Losh 2608e3e3a7aSWarner Losh 2618e3e3a7aSWarner Losh /* arrays larger than 'RANLIMIT' may use randomized pivots */ 2628e3e3a7aSWarner Losh #define RANLIMIT 100u 2638e3e3a7aSWarner Losh 2648e3e3a7aSWarner Losh 2658e3e3a7aSWarner Losh static void set2 (lua_State *L, IdxT i, IdxT j) { 2668e3e3a7aSWarner Losh lua_seti(L, 1, i); 2678e3e3a7aSWarner Losh lua_seti(L, 1, j); 2688e3e3a7aSWarner Losh } 2698e3e3a7aSWarner Losh 2708e3e3a7aSWarner Losh 2718e3e3a7aSWarner Losh /* 2728e3e3a7aSWarner Losh ** Return true iff value at stack index 'a' is less than the value at 2738e3e3a7aSWarner Losh ** index 'b' (according to the order of the sort). 2748e3e3a7aSWarner Losh */ 2758e3e3a7aSWarner Losh static int sort_comp (lua_State *L, int a, int b) { 2768e3e3a7aSWarner Losh if (lua_isnil(L, 2)) /* no function? */ 2778e3e3a7aSWarner Losh return lua_compare(L, a, b, LUA_OPLT); /* a < b */ 2788e3e3a7aSWarner Losh else { /* function */ 2798e3e3a7aSWarner Losh int res; 2808e3e3a7aSWarner Losh lua_pushvalue(L, 2); /* push function */ 2818e3e3a7aSWarner Losh lua_pushvalue(L, a-1); /* -1 to compensate function */ 2828e3e3a7aSWarner Losh lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ 2838e3e3a7aSWarner Losh lua_call(L, 2, 1); /* call function */ 2848e3e3a7aSWarner Losh res = lua_toboolean(L, -1); /* get result */ 2858e3e3a7aSWarner Losh lua_pop(L, 1); /* pop result */ 2868e3e3a7aSWarner Losh return res; 2878e3e3a7aSWarner Losh } 2888e3e3a7aSWarner Losh } 2898e3e3a7aSWarner Losh 2908e3e3a7aSWarner Losh 2918e3e3a7aSWarner Losh /* 2928e3e3a7aSWarner Losh ** Does the partition: Pivot P is at the top of the stack. 2938e3e3a7aSWarner Losh ** precondition: a[lo] <= P == a[up-1] <= a[up], 2948e3e3a7aSWarner Losh ** so it only needs to do the partition from lo + 1 to up - 2. 2958e3e3a7aSWarner Losh ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] 2968e3e3a7aSWarner Losh ** returns 'i'. 2978e3e3a7aSWarner Losh */ 2988e3e3a7aSWarner Losh static IdxT partition (lua_State *L, IdxT lo, IdxT up) { 2998e3e3a7aSWarner Losh IdxT i = lo; /* will be incremented before first use */ 3008e3e3a7aSWarner Losh IdxT j = up - 1; /* will be decremented before first use */ 3018e3e3a7aSWarner Losh /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ 3028e3e3a7aSWarner Losh for (;;) { 3038e3e3a7aSWarner Losh /* next loop: repeat ++i while a[i] < P */ 3040495ed39SKyle Evans while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { 305*8c784bb8SWarner Losh if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */ 3068e3e3a7aSWarner Losh luaL_error(L, "invalid order function for sorting"); 3078e3e3a7aSWarner Losh lua_pop(L, 1); /* remove a[i] */ 3088e3e3a7aSWarner Losh } 3098e3e3a7aSWarner Losh /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ 3108e3e3a7aSWarner Losh /* next loop: repeat --j while P < a[j] */ 3110495ed39SKyle Evans while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { 312*8c784bb8SWarner Losh if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */ 3138e3e3a7aSWarner Losh luaL_error(L, "invalid order function for sorting"); 3148e3e3a7aSWarner Losh lua_pop(L, 1); /* remove a[j] */ 3158e3e3a7aSWarner Losh } 3168e3e3a7aSWarner Losh /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ 3178e3e3a7aSWarner Losh if (j < i) { /* no elements out of place? */ 3188e3e3a7aSWarner Losh /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ 3198e3e3a7aSWarner Losh lua_pop(L, 1); /* pop a[j] */ 3208e3e3a7aSWarner Losh /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ 3218e3e3a7aSWarner Losh set2(L, up - 1, i); 3228e3e3a7aSWarner Losh return i; 3238e3e3a7aSWarner Losh } 3248e3e3a7aSWarner Losh /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ 3258e3e3a7aSWarner Losh set2(L, i, j); 3268e3e3a7aSWarner Losh } 3278e3e3a7aSWarner Losh } 3288e3e3a7aSWarner Losh 3298e3e3a7aSWarner Losh 3308e3e3a7aSWarner Losh /* 3318e3e3a7aSWarner Losh ** Choose an element in the middle (2nd-3th quarters) of [lo,up] 3328e3e3a7aSWarner Losh ** "randomized" by 'rnd' 3338e3e3a7aSWarner Losh */ 3348e3e3a7aSWarner Losh static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { 3358e3e3a7aSWarner Losh IdxT r4 = (up - lo) / 4; /* range/4 */ 3368e3e3a7aSWarner Losh IdxT p = rnd % (r4 * 2) + (lo + r4); 3378e3e3a7aSWarner Losh lua_assert(lo + r4 <= p && p <= up - r4); 3388e3e3a7aSWarner Losh return p; 3398e3e3a7aSWarner Losh } 3408e3e3a7aSWarner Losh 3418e3e3a7aSWarner Losh 3428e3e3a7aSWarner Losh /* 3430495ed39SKyle Evans ** Quicksort algorithm (recursive function) 3448e3e3a7aSWarner Losh */ 3458e3e3a7aSWarner Losh static void auxsort (lua_State *L, IdxT lo, IdxT up, 3468e3e3a7aSWarner Losh unsigned int rnd) { 3478e3e3a7aSWarner Losh while (lo < up) { /* loop for tail recursion */ 3488e3e3a7aSWarner Losh IdxT p; /* Pivot index */ 3498e3e3a7aSWarner Losh IdxT n; /* to be used later */ 3508e3e3a7aSWarner Losh /* sort elements 'lo', 'p', and 'up' */ 3518e3e3a7aSWarner Losh lua_geti(L, 1, lo); 3528e3e3a7aSWarner Losh lua_geti(L, 1, up); 3538e3e3a7aSWarner Losh if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ 3548e3e3a7aSWarner Losh set2(L, lo, up); /* swap a[lo] - a[up] */ 3558e3e3a7aSWarner Losh else 3568e3e3a7aSWarner Losh lua_pop(L, 2); /* remove both values */ 3578e3e3a7aSWarner Losh if (up - lo == 1) /* only 2 elements? */ 3588e3e3a7aSWarner Losh return; /* already sorted */ 3598e3e3a7aSWarner Losh if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ 3608e3e3a7aSWarner Losh p = (lo + up)/2; /* middle element is a good pivot */ 3618e3e3a7aSWarner Losh else /* for larger intervals, it is worth a random pivot */ 3628e3e3a7aSWarner Losh p = choosePivot(lo, up, rnd); 3638e3e3a7aSWarner Losh lua_geti(L, 1, p); 3648e3e3a7aSWarner Losh lua_geti(L, 1, lo); 3658e3e3a7aSWarner Losh if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ 3668e3e3a7aSWarner Losh set2(L, p, lo); /* swap a[p] - a[lo] */ 3678e3e3a7aSWarner Losh else { 3688e3e3a7aSWarner Losh lua_pop(L, 1); /* remove a[lo] */ 3698e3e3a7aSWarner Losh lua_geti(L, 1, up); 3708e3e3a7aSWarner Losh if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ 3718e3e3a7aSWarner Losh set2(L, p, up); /* swap a[up] - a[p] */ 3728e3e3a7aSWarner Losh else 3738e3e3a7aSWarner Losh lua_pop(L, 2); 3748e3e3a7aSWarner Losh } 3758e3e3a7aSWarner Losh if (up - lo == 2) /* only 3 elements? */ 3768e3e3a7aSWarner Losh return; /* already sorted */ 3778e3e3a7aSWarner Losh lua_geti(L, 1, p); /* get middle element (Pivot) */ 3788e3e3a7aSWarner Losh lua_pushvalue(L, -1); /* push Pivot */ 3798e3e3a7aSWarner Losh lua_geti(L, 1, up - 1); /* push a[up - 1] */ 3808e3e3a7aSWarner Losh set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ 3818e3e3a7aSWarner Losh p = partition(L, lo, up); 3828e3e3a7aSWarner Losh /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ 3838e3e3a7aSWarner Losh if (p - lo < up - p) { /* lower interval is smaller? */ 3848e3e3a7aSWarner Losh auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ 3858e3e3a7aSWarner Losh n = p - lo; /* size of smaller interval */ 3868e3e3a7aSWarner Losh lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ 3878e3e3a7aSWarner Losh } 3888e3e3a7aSWarner Losh else { 3898e3e3a7aSWarner Losh auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ 3908e3e3a7aSWarner Losh n = up - p; /* size of smaller interval */ 3918e3e3a7aSWarner Losh up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ 3928e3e3a7aSWarner Losh } 3938e3e3a7aSWarner Losh if ((up - lo) / 128 > n) /* partition too imbalanced? */ 3948e3e3a7aSWarner Losh rnd = l_randomizePivot(); /* try a new randomization */ 3958e3e3a7aSWarner Losh } /* tail call auxsort(L, lo, up, rnd) */ 3968e3e3a7aSWarner Losh } 3978e3e3a7aSWarner Losh 3988e3e3a7aSWarner Losh 3998e3e3a7aSWarner Losh static int sort (lua_State *L) { 4008e3e3a7aSWarner Losh lua_Integer n = aux_getn(L, 1, TAB_RW); 4018e3e3a7aSWarner Losh if (n > 1) { /* non-trivial interval? */ 4028e3e3a7aSWarner Losh luaL_argcheck(L, n < INT_MAX, 1, "array too big"); 4038e3e3a7aSWarner Losh if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ 4048e3e3a7aSWarner Losh luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ 4058e3e3a7aSWarner Losh lua_settop(L, 2); /* make sure there are two arguments */ 4068e3e3a7aSWarner Losh auxsort(L, 1, (IdxT)n, 0); 4078e3e3a7aSWarner Losh } 4088e3e3a7aSWarner Losh return 0; 4098e3e3a7aSWarner Losh } 4108e3e3a7aSWarner Losh 4118e3e3a7aSWarner Losh /* }====================================================== */ 4128e3e3a7aSWarner Losh 4138e3e3a7aSWarner Losh 4148e3e3a7aSWarner Losh static const luaL_Reg tab_funcs[] = { 4158e3e3a7aSWarner Losh {"concat", tconcat}, 4168e3e3a7aSWarner Losh {"insert", tinsert}, 4170495ed39SKyle Evans {"pack", tpack}, 4180495ed39SKyle Evans {"unpack", tunpack}, 4198e3e3a7aSWarner Losh {"remove", tremove}, 4208e3e3a7aSWarner Losh {"move", tmove}, 4218e3e3a7aSWarner Losh {"sort", sort}, 4228e3e3a7aSWarner Losh {NULL, NULL} 4238e3e3a7aSWarner Losh }; 4248e3e3a7aSWarner Losh 4258e3e3a7aSWarner Losh 4268e3e3a7aSWarner Losh LUAMOD_API int luaopen_table (lua_State *L) { 4278e3e3a7aSWarner Losh luaL_newlib(L, tab_funcs); 4288e3e3a7aSWarner Losh return 1; 4298e3e3a7aSWarner Losh } 4308e3e3a7aSWarner Losh 431