1*8e3e3a7aSWarner Losh /* 2*8e3e3a7aSWarner Losh ** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ 3*8e3e3a7aSWarner Losh ** Library for Table Manipulation 4*8e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 5*8e3e3a7aSWarner Losh */ 6*8e3e3a7aSWarner Losh 7*8e3e3a7aSWarner Losh #define ltablib_c 8*8e3e3a7aSWarner Losh #define LUA_LIB 9*8e3e3a7aSWarner Losh 10*8e3e3a7aSWarner Losh #include "lprefix.h" 11*8e3e3a7aSWarner Losh 12*8e3e3a7aSWarner Losh 13*8e3e3a7aSWarner Losh #include <limits.h> 14*8e3e3a7aSWarner Losh #include <stddef.h> 15*8e3e3a7aSWarner Losh #include <string.h> 16*8e3e3a7aSWarner Losh 17*8e3e3a7aSWarner Losh #include "lua.h" 18*8e3e3a7aSWarner Losh 19*8e3e3a7aSWarner Losh #include "lauxlib.h" 20*8e3e3a7aSWarner Losh #include "lualib.h" 21*8e3e3a7aSWarner Losh 22*8e3e3a7aSWarner Losh 23*8e3e3a7aSWarner Losh /* 24*8e3e3a7aSWarner Losh ** Operations that an object must define to mimic a table 25*8e3e3a7aSWarner Losh ** (some functions only need some of them) 26*8e3e3a7aSWarner Losh */ 27*8e3e3a7aSWarner Losh #define TAB_R 1 /* read */ 28*8e3e3a7aSWarner Losh #define TAB_W 2 /* write */ 29*8e3e3a7aSWarner Losh #define TAB_L 4 /* length */ 30*8e3e3a7aSWarner Losh #define TAB_RW (TAB_R | TAB_W) /* read/write */ 31*8e3e3a7aSWarner Losh 32*8e3e3a7aSWarner Losh 33*8e3e3a7aSWarner Losh #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) 34*8e3e3a7aSWarner Losh 35*8e3e3a7aSWarner Losh 36*8e3e3a7aSWarner Losh static int checkfield (lua_State *L, const char *key, int n) { 37*8e3e3a7aSWarner Losh lua_pushstring(L, key); 38*8e3e3a7aSWarner Losh return (lua_rawget(L, -n) != LUA_TNIL); 39*8e3e3a7aSWarner Losh } 40*8e3e3a7aSWarner Losh 41*8e3e3a7aSWarner Losh 42*8e3e3a7aSWarner Losh /* 43*8e3e3a7aSWarner Losh ** Check that 'arg' either is a table or can behave like one (that is, 44*8e3e3a7aSWarner Losh ** has a metatable with the required metamethods) 45*8e3e3a7aSWarner Losh */ 46*8e3e3a7aSWarner Losh static void checktab (lua_State *L, int arg, int what) { 47*8e3e3a7aSWarner Losh if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ 48*8e3e3a7aSWarner Losh int n = 1; /* number of elements to pop */ 49*8e3e3a7aSWarner Losh if (lua_getmetatable(L, arg) && /* must have metatable */ 50*8e3e3a7aSWarner Losh (!(what & TAB_R) || checkfield(L, "__index", ++n)) && 51*8e3e3a7aSWarner Losh (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && 52*8e3e3a7aSWarner Losh (!(what & TAB_L) || checkfield(L, "__len", ++n))) { 53*8e3e3a7aSWarner Losh lua_pop(L, n); /* pop metatable and tested metamethods */ 54*8e3e3a7aSWarner Losh } 55*8e3e3a7aSWarner Losh else 56*8e3e3a7aSWarner Losh luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ 57*8e3e3a7aSWarner Losh } 58*8e3e3a7aSWarner Losh } 59*8e3e3a7aSWarner Losh 60*8e3e3a7aSWarner Losh 61*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MAXN) 62*8e3e3a7aSWarner Losh static int maxn (lua_State *L) { 63*8e3e3a7aSWarner Losh lua_Number max = 0; 64*8e3e3a7aSWarner Losh luaL_checktype(L, 1, LUA_TTABLE); 65*8e3e3a7aSWarner Losh lua_pushnil(L); /* first key */ 66*8e3e3a7aSWarner Losh while (lua_next(L, 1)) { 67*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove value */ 68*8e3e3a7aSWarner Losh if (lua_type(L, -1) == LUA_TNUMBER) { 69*8e3e3a7aSWarner Losh lua_Number v = lua_tonumber(L, -1); 70*8e3e3a7aSWarner Losh if (v > max) max = v; 71*8e3e3a7aSWarner Losh } 72*8e3e3a7aSWarner Losh } 73*8e3e3a7aSWarner Losh lua_pushnumber(L, max); 74*8e3e3a7aSWarner Losh return 1; 75*8e3e3a7aSWarner Losh } 76*8e3e3a7aSWarner Losh #endif 77*8e3e3a7aSWarner Losh 78*8e3e3a7aSWarner Losh 79*8e3e3a7aSWarner Losh static int tinsert (lua_State *L) { 80*8e3e3a7aSWarner Losh lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ 81*8e3e3a7aSWarner Losh lua_Integer pos; /* where to insert new element */ 82*8e3e3a7aSWarner Losh switch (lua_gettop(L)) { 83*8e3e3a7aSWarner Losh case 2: { /* called with only 2 arguments */ 84*8e3e3a7aSWarner Losh pos = e; /* insert new element at the end */ 85*8e3e3a7aSWarner Losh break; 86*8e3e3a7aSWarner Losh } 87*8e3e3a7aSWarner Losh case 3: { 88*8e3e3a7aSWarner Losh lua_Integer i; 89*8e3e3a7aSWarner Losh pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ 90*8e3e3a7aSWarner Losh luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); 91*8e3e3a7aSWarner Losh for (i = e; i > pos; i--) { /* move up elements */ 92*8e3e3a7aSWarner Losh lua_geti(L, 1, i - 1); 93*8e3e3a7aSWarner Losh lua_seti(L, 1, i); /* t[i] = t[i - 1] */ 94*8e3e3a7aSWarner Losh } 95*8e3e3a7aSWarner Losh break; 96*8e3e3a7aSWarner Losh } 97*8e3e3a7aSWarner Losh default: { 98*8e3e3a7aSWarner Losh return luaL_error(L, "wrong number of arguments to 'insert'"); 99*8e3e3a7aSWarner Losh } 100*8e3e3a7aSWarner Losh } 101*8e3e3a7aSWarner Losh lua_seti(L, 1, pos); /* t[pos] = v */ 102*8e3e3a7aSWarner Losh return 0; 103*8e3e3a7aSWarner Losh } 104*8e3e3a7aSWarner Losh 105*8e3e3a7aSWarner Losh 106*8e3e3a7aSWarner Losh static int tremove (lua_State *L) { 107*8e3e3a7aSWarner Losh lua_Integer size = aux_getn(L, 1, TAB_RW); 108*8e3e3a7aSWarner Losh lua_Integer pos = luaL_optinteger(L, 2, size); 109*8e3e3a7aSWarner Losh if (pos != size) /* validate 'pos' if given */ 110*8e3e3a7aSWarner Losh luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); 111*8e3e3a7aSWarner Losh lua_geti(L, 1, pos); /* result = t[pos] */ 112*8e3e3a7aSWarner Losh for ( ; pos < size; pos++) { 113*8e3e3a7aSWarner Losh lua_geti(L, 1, pos + 1); 114*8e3e3a7aSWarner Losh lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ 115*8e3e3a7aSWarner Losh } 116*8e3e3a7aSWarner Losh lua_pushnil(L); 117*8e3e3a7aSWarner Losh lua_seti(L, 1, pos); /* t[pos] = nil */ 118*8e3e3a7aSWarner Losh return 1; 119*8e3e3a7aSWarner Losh } 120*8e3e3a7aSWarner Losh 121*8e3e3a7aSWarner Losh 122*8e3e3a7aSWarner Losh /* 123*8e3e3a7aSWarner Losh ** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever 124*8e3e3a7aSWarner Losh ** possible, copy in increasing order, which is better for rehashing. 125*8e3e3a7aSWarner Losh ** "possible" means destination after original range, or smaller 126*8e3e3a7aSWarner Losh ** than origin, or copying to another table. 127*8e3e3a7aSWarner Losh */ 128*8e3e3a7aSWarner Losh static int tmove (lua_State *L) { 129*8e3e3a7aSWarner Losh lua_Integer f = luaL_checkinteger(L, 2); 130*8e3e3a7aSWarner Losh lua_Integer e = luaL_checkinteger(L, 3); 131*8e3e3a7aSWarner Losh lua_Integer t = luaL_checkinteger(L, 4); 132*8e3e3a7aSWarner Losh int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ 133*8e3e3a7aSWarner Losh checktab(L, 1, TAB_R); 134*8e3e3a7aSWarner Losh checktab(L, tt, TAB_W); 135*8e3e3a7aSWarner Losh if (e >= f) { /* otherwise, nothing to move */ 136*8e3e3a7aSWarner Losh lua_Integer n, i; 137*8e3e3a7aSWarner Losh luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, 138*8e3e3a7aSWarner Losh "too many elements to move"); 139*8e3e3a7aSWarner Losh n = e - f + 1; /* number of elements to move */ 140*8e3e3a7aSWarner Losh luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, 141*8e3e3a7aSWarner Losh "destination wrap around"); 142*8e3e3a7aSWarner Losh if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { 143*8e3e3a7aSWarner Losh for (i = 0; i < n; i++) { 144*8e3e3a7aSWarner Losh lua_geti(L, 1, f + i); 145*8e3e3a7aSWarner Losh lua_seti(L, tt, t + i); 146*8e3e3a7aSWarner Losh } 147*8e3e3a7aSWarner Losh } 148*8e3e3a7aSWarner Losh else { 149*8e3e3a7aSWarner Losh for (i = n - 1; i >= 0; i--) { 150*8e3e3a7aSWarner Losh lua_geti(L, 1, f + i); 151*8e3e3a7aSWarner Losh lua_seti(L, tt, t + i); 152*8e3e3a7aSWarner Losh } 153*8e3e3a7aSWarner Losh } 154*8e3e3a7aSWarner Losh } 155*8e3e3a7aSWarner Losh lua_pushvalue(L, tt); /* return destination table */ 156*8e3e3a7aSWarner Losh return 1; 157*8e3e3a7aSWarner Losh } 158*8e3e3a7aSWarner Losh 159*8e3e3a7aSWarner Losh 160*8e3e3a7aSWarner Losh static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { 161*8e3e3a7aSWarner Losh lua_geti(L, 1, i); 162*8e3e3a7aSWarner Losh if (!lua_isstring(L, -1)) 163*8e3e3a7aSWarner Losh luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", 164*8e3e3a7aSWarner Losh luaL_typename(L, -1), i); 165*8e3e3a7aSWarner Losh luaL_addvalue(b); 166*8e3e3a7aSWarner Losh } 167*8e3e3a7aSWarner Losh 168*8e3e3a7aSWarner Losh 169*8e3e3a7aSWarner Losh static int tconcat (lua_State *L) { 170*8e3e3a7aSWarner Losh luaL_Buffer b; 171*8e3e3a7aSWarner Losh lua_Integer last = aux_getn(L, 1, TAB_R); 172*8e3e3a7aSWarner Losh size_t lsep; 173*8e3e3a7aSWarner Losh const char *sep = luaL_optlstring(L, 2, "", &lsep); 174*8e3e3a7aSWarner Losh lua_Integer i = luaL_optinteger(L, 3, 1); 175*8e3e3a7aSWarner Losh last = luaL_optinteger(L, 4, last); 176*8e3e3a7aSWarner Losh luaL_buffinit(L, &b); 177*8e3e3a7aSWarner Losh for (; i < last; i++) { 178*8e3e3a7aSWarner Losh addfield(L, &b, i); 179*8e3e3a7aSWarner Losh luaL_addlstring(&b, sep, lsep); 180*8e3e3a7aSWarner Losh } 181*8e3e3a7aSWarner Losh if (i == last) /* add last value (if interval was not empty) */ 182*8e3e3a7aSWarner Losh addfield(L, &b, i); 183*8e3e3a7aSWarner Losh luaL_pushresult(&b); 184*8e3e3a7aSWarner Losh return 1; 185*8e3e3a7aSWarner Losh } 186*8e3e3a7aSWarner Losh 187*8e3e3a7aSWarner Losh 188*8e3e3a7aSWarner Losh /* 189*8e3e3a7aSWarner Losh ** {====================================================== 190*8e3e3a7aSWarner Losh ** Pack/unpack 191*8e3e3a7aSWarner Losh ** ======================================================= 192*8e3e3a7aSWarner Losh */ 193*8e3e3a7aSWarner Losh 194*8e3e3a7aSWarner Losh static int pack (lua_State *L) { 195*8e3e3a7aSWarner Losh int i; 196*8e3e3a7aSWarner Losh int n = lua_gettop(L); /* number of elements to pack */ 197*8e3e3a7aSWarner Losh lua_createtable(L, n, 1); /* create result table */ 198*8e3e3a7aSWarner Losh lua_insert(L, 1); /* put it at index 1 */ 199*8e3e3a7aSWarner Losh for (i = n; i >= 1; i--) /* assign elements */ 200*8e3e3a7aSWarner Losh lua_seti(L, 1, i); 201*8e3e3a7aSWarner Losh lua_pushinteger(L, n); 202*8e3e3a7aSWarner Losh lua_setfield(L, 1, "n"); /* t.n = number of elements */ 203*8e3e3a7aSWarner Losh return 1; /* return table */ 204*8e3e3a7aSWarner Losh } 205*8e3e3a7aSWarner Losh 206*8e3e3a7aSWarner Losh 207*8e3e3a7aSWarner Losh static int unpack (lua_State *L) { 208*8e3e3a7aSWarner Losh lua_Unsigned n; 209*8e3e3a7aSWarner Losh lua_Integer i = luaL_optinteger(L, 2, 1); 210*8e3e3a7aSWarner Losh lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); 211*8e3e3a7aSWarner Losh if (i > e) return 0; /* empty range */ 212*8e3e3a7aSWarner Losh n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ 213*8e3e3a7aSWarner Losh if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) 214*8e3e3a7aSWarner Losh return luaL_error(L, "too many results to unpack"); 215*8e3e3a7aSWarner Losh for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ 216*8e3e3a7aSWarner Losh lua_geti(L, 1, i); 217*8e3e3a7aSWarner Losh } 218*8e3e3a7aSWarner Losh lua_geti(L, 1, e); /* push last element */ 219*8e3e3a7aSWarner Losh return (int)n; 220*8e3e3a7aSWarner Losh } 221*8e3e3a7aSWarner Losh 222*8e3e3a7aSWarner Losh /* }====================================================== */ 223*8e3e3a7aSWarner Losh 224*8e3e3a7aSWarner Losh 225*8e3e3a7aSWarner Losh 226*8e3e3a7aSWarner Losh /* 227*8e3e3a7aSWarner Losh ** {====================================================== 228*8e3e3a7aSWarner Losh ** Quicksort 229*8e3e3a7aSWarner Losh ** (based on 'Algorithms in MODULA-3', Robert Sedgewick; 230*8e3e3a7aSWarner Losh ** Addison-Wesley, 1993.) 231*8e3e3a7aSWarner Losh ** ======================================================= 232*8e3e3a7aSWarner Losh */ 233*8e3e3a7aSWarner Losh 234*8e3e3a7aSWarner Losh 235*8e3e3a7aSWarner Losh /* type for array indices */ 236*8e3e3a7aSWarner Losh typedef unsigned int IdxT; 237*8e3e3a7aSWarner Losh 238*8e3e3a7aSWarner Losh 239*8e3e3a7aSWarner Losh /* 240*8e3e3a7aSWarner Losh ** Produce a "random" 'unsigned int' to randomize pivot choice. This 241*8e3e3a7aSWarner Losh ** macro is used only when 'sort' detects a big imbalance in the result 242*8e3e3a7aSWarner Losh ** of a partition. (If you don't want/need this "randomness", ~0 is a 243*8e3e3a7aSWarner Losh ** good choice.) 244*8e3e3a7aSWarner Losh */ 245*8e3e3a7aSWarner Losh #if !defined(l_randomizePivot) /* { */ 246*8e3e3a7aSWarner Losh 247*8e3e3a7aSWarner Losh #include <time.h> 248*8e3e3a7aSWarner Losh 249*8e3e3a7aSWarner Losh /* size of 'e' measured in number of 'unsigned int's */ 250*8e3e3a7aSWarner Losh #define sof(e) (sizeof(e) / sizeof(unsigned int)) 251*8e3e3a7aSWarner Losh 252*8e3e3a7aSWarner Losh /* 253*8e3e3a7aSWarner Losh ** Use 'time' and 'clock' as sources of "randomness". Because we don't 254*8e3e3a7aSWarner Losh ** know the types 'clock_t' and 'time_t', we cannot cast them to 255*8e3e3a7aSWarner Losh ** anything without risking overflows. A safe way to use their values 256*8e3e3a7aSWarner Losh ** is to copy them to an array of a known type and use the array values. 257*8e3e3a7aSWarner Losh */ 258*8e3e3a7aSWarner Losh static unsigned int l_randomizePivot (void) { 259*8e3e3a7aSWarner Losh clock_t c = clock(); 260*8e3e3a7aSWarner Losh time_t t = time(NULL); 261*8e3e3a7aSWarner Losh unsigned int buff[sof(c) + sof(t)]; 262*8e3e3a7aSWarner Losh unsigned int i, rnd = 0; 263*8e3e3a7aSWarner Losh memcpy(buff, &c, sof(c) * sizeof(unsigned int)); 264*8e3e3a7aSWarner Losh memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); 265*8e3e3a7aSWarner Losh for (i = 0; i < sof(buff); i++) 266*8e3e3a7aSWarner Losh rnd += buff[i]; 267*8e3e3a7aSWarner Losh return rnd; 268*8e3e3a7aSWarner Losh } 269*8e3e3a7aSWarner Losh 270*8e3e3a7aSWarner Losh #endif /* } */ 271*8e3e3a7aSWarner Losh 272*8e3e3a7aSWarner Losh 273*8e3e3a7aSWarner Losh /* arrays larger than 'RANLIMIT' may use randomized pivots */ 274*8e3e3a7aSWarner Losh #define RANLIMIT 100u 275*8e3e3a7aSWarner Losh 276*8e3e3a7aSWarner Losh 277*8e3e3a7aSWarner Losh static void set2 (lua_State *L, IdxT i, IdxT j) { 278*8e3e3a7aSWarner Losh lua_seti(L, 1, i); 279*8e3e3a7aSWarner Losh lua_seti(L, 1, j); 280*8e3e3a7aSWarner Losh } 281*8e3e3a7aSWarner Losh 282*8e3e3a7aSWarner Losh 283*8e3e3a7aSWarner Losh /* 284*8e3e3a7aSWarner Losh ** Return true iff value at stack index 'a' is less than the value at 285*8e3e3a7aSWarner Losh ** index 'b' (according to the order of the sort). 286*8e3e3a7aSWarner Losh */ 287*8e3e3a7aSWarner Losh static int sort_comp (lua_State *L, int a, int b) { 288*8e3e3a7aSWarner Losh if (lua_isnil(L, 2)) /* no function? */ 289*8e3e3a7aSWarner Losh return lua_compare(L, a, b, LUA_OPLT); /* a < b */ 290*8e3e3a7aSWarner Losh else { /* function */ 291*8e3e3a7aSWarner Losh int res; 292*8e3e3a7aSWarner Losh lua_pushvalue(L, 2); /* push function */ 293*8e3e3a7aSWarner Losh lua_pushvalue(L, a-1); /* -1 to compensate function */ 294*8e3e3a7aSWarner Losh lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ 295*8e3e3a7aSWarner Losh lua_call(L, 2, 1); /* call function */ 296*8e3e3a7aSWarner Losh res = lua_toboolean(L, -1); /* get result */ 297*8e3e3a7aSWarner Losh lua_pop(L, 1); /* pop result */ 298*8e3e3a7aSWarner Losh return res; 299*8e3e3a7aSWarner Losh } 300*8e3e3a7aSWarner Losh } 301*8e3e3a7aSWarner Losh 302*8e3e3a7aSWarner Losh 303*8e3e3a7aSWarner Losh /* 304*8e3e3a7aSWarner Losh ** Does the partition: Pivot P is at the top of the stack. 305*8e3e3a7aSWarner Losh ** precondition: a[lo] <= P == a[up-1] <= a[up], 306*8e3e3a7aSWarner Losh ** so it only needs to do the partition from lo + 1 to up - 2. 307*8e3e3a7aSWarner Losh ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] 308*8e3e3a7aSWarner Losh ** returns 'i'. 309*8e3e3a7aSWarner Losh */ 310*8e3e3a7aSWarner Losh static IdxT partition (lua_State *L, IdxT lo, IdxT up) { 311*8e3e3a7aSWarner Losh IdxT i = lo; /* will be incremented before first use */ 312*8e3e3a7aSWarner Losh IdxT j = up - 1; /* will be decremented before first use */ 313*8e3e3a7aSWarner Losh /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ 314*8e3e3a7aSWarner Losh for (;;) { 315*8e3e3a7aSWarner Losh /* next loop: repeat ++i while a[i] < P */ 316*8e3e3a7aSWarner Losh while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { 317*8e3e3a7aSWarner Losh if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ 318*8e3e3a7aSWarner Losh luaL_error(L, "invalid order function for sorting"); 319*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove a[i] */ 320*8e3e3a7aSWarner Losh } 321*8e3e3a7aSWarner Losh /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ 322*8e3e3a7aSWarner Losh /* next loop: repeat --j while P < a[j] */ 323*8e3e3a7aSWarner Losh while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { 324*8e3e3a7aSWarner Losh if (j < i) /* j < i but a[j] > P ?? */ 325*8e3e3a7aSWarner Losh luaL_error(L, "invalid order function for sorting"); 326*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove a[j] */ 327*8e3e3a7aSWarner Losh } 328*8e3e3a7aSWarner Losh /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ 329*8e3e3a7aSWarner Losh if (j < i) { /* no elements out of place? */ 330*8e3e3a7aSWarner Losh /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ 331*8e3e3a7aSWarner Losh lua_pop(L, 1); /* pop a[j] */ 332*8e3e3a7aSWarner Losh /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ 333*8e3e3a7aSWarner Losh set2(L, up - 1, i); 334*8e3e3a7aSWarner Losh return i; 335*8e3e3a7aSWarner Losh } 336*8e3e3a7aSWarner Losh /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ 337*8e3e3a7aSWarner Losh set2(L, i, j); 338*8e3e3a7aSWarner Losh } 339*8e3e3a7aSWarner Losh } 340*8e3e3a7aSWarner Losh 341*8e3e3a7aSWarner Losh 342*8e3e3a7aSWarner Losh /* 343*8e3e3a7aSWarner Losh ** Choose an element in the middle (2nd-3th quarters) of [lo,up] 344*8e3e3a7aSWarner Losh ** "randomized" by 'rnd' 345*8e3e3a7aSWarner Losh */ 346*8e3e3a7aSWarner Losh static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { 347*8e3e3a7aSWarner Losh IdxT r4 = (up - lo) / 4; /* range/4 */ 348*8e3e3a7aSWarner Losh IdxT p = rnd % (r4 * 2) + (lo + r4); 349*8e3e3a7aSWarner Losh lua_assert(lo + r4 <= p && p <= up - r4); 350*8e3e3a7aSWarner Losh return p; 351*8e3e3a7aSWarner Losh } 352*8e3e3a7aSWarner Losh 353*8e3e3a7aSWarner Losh 354*8e3e3a7aSWarner Losh /* 355*8e3e3a7aSWarner Losh ** QuickSort algorithm (recursive function) 356*8e3e3a7aSWarner Losh */ 357*8e3e3a7aSWarner Losh static void auxsort (lua_State *L, IdxT lo, IdxT up, 358*8e3e3a7aSWarner Losh unsigned int rnd) { 359*8e3e3a7aSWarner Losh while (lo < up) { /* loop for tail recursion */ 360*8e3e3a7aSWarner Losh IdxT p; /* Pivot index */ 361*8e3e3a7aSWarner Losh IdxT n; /* to be used later */ 362*8e3e3a7aSWarner Losh /* sort elements 'lo', 'p', and 'up' */ 363*8e3e3a7aSWarner Losh lua_geti(L, 1, lo); 364*8e3e3a7aSWarner Losh lua_geti(L, 1, up); 365*8e3e3a7aSWarner Losh if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ 366*8e3e3a7aSWarner Losh set2(L, lo, up); /* swap a[lo] - a[up] */ 367*8e3e3a7aSWarner Losh else 368*8e3e3a7aSWarner Losh lua_pop(L, 2); /* remove both values */ 369*8e3e3a7aSWarner Losh if (up - lo == 1) /* only 2 elements? */ 370*8e3e3a7aSWarner Losh return; /* already sorted */ 371*8e3e3a7aSWarner Losh if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ 372*8e3e3a7aSWarner Losh p = (lo + up)/2; /* middle element is a good pivot */ 373*8e3e3a7aSWarner Losh else /* for larger intervals, it is worth a random pivot */ 374*8e3e3a7aSWarner Losh p = choosePivot(lo, up, rnd); 375*8e3e3a7aSWarner Losh lua_geti(L, 1, p); 376*8e3e3a7aSWarner Losh lua_geti(L, 1, lo); 377*8e3e3a7aSWarner Losh if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ 378*8e3e3a7aSWarner Losh set2(L, p, lo); /* swap a[p] - a[lo] */ 379*8e3e3a7aSWarner Losh else { 380*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove a[lo] */ 381*8e3e3a7aSWarner Losh lua_geti(L, 1, up); 382*8e3e3a7aSWarner Losh if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ 383*8e3e3a7aSWarner Losh set2(L, p, up); /* swap a[up] - a[p] */ 384*8e3e3a7aSWarner Losh else 385*8e3e3a7aSWarner Losh lua_pop(L, 2); 386*8e3e3a7aSWarner Losh } 387*8e3e3a7aSWarner Losh if (up - lo == 2) /* only 3 elements? */ 388*8e3e3a7aSWarner Losh return; /* already sorted */ 389*8e3e3a7aSWarner Losh lua_geti(L, 1, p); /* get middle element (Pivot) */ 390*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); /* push Pivot */ 391*8e3e3a7aSWarner Losh lua_geti(L, 1, up - 1); /* push a[up - 1] */ 392*8e3e3a7aSWarner Losh set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ 393*8e3e3a7aSWarner Losh p = partition(L, lo, up); 394*8e3e3a7aSWarner Losh /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ 395*8e3e3a7aSWarner Losh if (p - lo < up - p) { /* lower interval is smaller? */ 396*8e3e3a7aSWarner Losh auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ 397*8e3e3a7aSWarner Losh n = p - lo; /* size of smaller interval */ 398*8e3e3a7aSWarner Losh lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ 399*8e3e3a7aSWarner Losh } 400*8e3e3a7aSWarner Losh else { 401*8e3e3a7aSWarner Losh auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ 402*8e3e3a7aSWarner Losh n = up - p; /* size of smaller interval */ 403*8e3e3a7aSWarner Losh up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ 404*8e3e3a7aSWarner Losh } 405*8e3e3a7aSWarner Losh if ((up - lo) / 128 > n) /* partition too imbalanced? */ 406*8e3e3a7aSWarner Losh rnd = l_randomizePivot(); /* try a new randomization */ 407*8e3e3a7aSWarner Losh } /* tail call auxsort(L, lo, up, rnd) */ 408*8e3e3a7aSWarner Losh } 409*8e3e3a7aSWarner Losh 410*8e3e3a7aSWarner Losh 411*8e3e3a7aSWarner Losh static int sort (lua_State *L) { 412*8e3e3a7aSWarner Losh lua_Integer n = aux_getn(L, 1, TAB_RW); 413*8e3e3a7aSWarner Losh if (n > 1) { /* non-trivial interval? */ 414*8e3e3a7aSWarner Losh luaL_argcheck(L, n < INT_MAX, 1, "array too big"); 415*8e3e3a7aSWarner Losh if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ 416*8e3e3a7aSWarner Losh luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ 417*8e3e3a7aSWarner Losh lua_settop(L, 2); /* make sure there are two arguments */ 418*8e3e3a7aSWarner Losh auxsort(L, 1, (IdxT)n, 0); 419*8e3e3a7aSWarner Losh } 420*8e3e3a7aSWarner Losh return 0; 421*8e3e3a7aSWarner Losh } 422*8e3e3a7aSWarner Losh 423*8e3e3a7aSWarner Losh /* }====================================================== */ 424*8e3e3a7aSWarner Losh 425*8e3e3a7aSWarner Losh 426*8e3e3a7aSWarner Losh static const luaL_Reg tab_funcs[] = { 427*8e3e3a7aSWarner Losh {"concat", tconcat}, 428*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MAXN) 429*8e3e3a7aSWarner Losh {"maxn", maxn}, 430*8e3e3a7aSWarner Losh #endif 431*8e3e3a7aSWarner Losh {"insert", tinsert}, 432*8e3e3a7aSWarner Losh {"pack", pack}, 433*8e3e3a7aSWarner Losh {"unpack", unpack}, 434*8e3e3a7aSWarner Losh {"remove", tremove}, 435*8e3e3a7aSWarner Losh {"move", tmove}, 436*8e3e3a7aSWarner Losh {"sort", sort}, 437*8e3e3a7aSWarner Losh {NULL, NULL} 438*8e3e3a7aSWarner Losh }; 439*8e3e3a7aSWarner Losh 440*8e3e3a7aSWarner Losh 441*8e3e3a7aSWarner Losh LUAMOD_API int luaopen_table (lua_State *L) { 442*8e3e3a7aSWarner Losh luaL_newlib(L, tab_funcs); 443*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_UNPACK) 444*8e3e3a7aSWarner Losh /* _G.unpack = table.unpack */ 445*8e3e3a7aSWarner Losh lua_getfield(L, -1, "unpack"); 446*8e3e3a7aSWarner Losh lua_setglobal(L, "unpack"); 447*8e3e3a7aSWarner Losh #endif 448*8e3e3a7aSWarner Losh return 1; 449*8e3e3a7aSWarner Losh } 450*8e3e3a7aSWarner Losh 451