1 /* $NetBSD: ltablib.c,v 1.3 2015/02/02 14:03:05 lneto Exp $ */ 2 3 /* 4 ** Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp 5 ** Library for Table Manipulation 6 ** See Copyright Notice in lua.h 7 */ 8 9 #define ltablib_c 10 #define LUA_LIB 11 12 #include "lprefix.h" 13 14 15 #ifndef _KERNEL 16 #include <limits.h> 17 #include <stddef.h> 18 #endif 19 20 #include "lua.h" 21 22 #include "lauxlib.h" 23 #include "lualib.h" 24 25 26 27 /* 28 ** Structure with table-access functions 29 */ 30 typedef struct { 31 int (*geti) (lua_State *L, int idx, lua_Integer n); 32 void (*seti) (lua_State *L, int idx, lua_Integer n); 33 } TabA; 34 35 36 /* 37 ** Check that 'arg' has a table and set access functions in 'ta' to raw 38 ** or non-raw according to the presence of corresponding metamethods. 39 */ 40 static void checktab (lua_State *L, int arg, TabA *ta) { 41 ta->geti = NULL; ta->seti = NULL; 42 if (lua_getmetatable(L, arg)) { 43 lua_pushliteral(L, "__index"); /* 'index' metamethod */ 44 if (lua_rawget(L, -2) != LUA_TNIL) 45 ta->geti = lua_geti; 46 lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */ 47 if (lua_rawget(L, -3) != LUA_TNIL) 48 ta->seti = lua_seti; 49 lua_pop(L, 3); /* pop metatable plus both metamethods */ 50 } 51 if (ta->geti == NULL || ta->seti == NULL) { 52 luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */ 53 if (ta->geti == NULL) ta->geti = lua_rawgeti; 54 if (ta->seti == NULL) ta->seti = lua_rawseti; 55 } 56 } 57 58 59 #define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n)) 60 61 62 #if defined(LUA_COMPAT_MAXN) 63 static int maxn (lua_State *L) { 64 lua_Number max = 0; 65 luaL_checktype(L, 1, LUA_TTABLE); 66 lua_pushnil(L); /* first key */ 67 while (lua_next(L, 1)) { 68 lua_pop(L, 1); /* remove value */ 69 if (lua_type(L, -1) == LUA_TNUMBER) { 70 lua_Number v = lua_tonumber(L, -1); 71 if (v > max) max = v; 72 } 73 } 74 lua_pushnumber(L, max); 75 return 1; 76 } 77 #endif 78 79 80 static int tinsert (lua_State *L) { 81 TabA ta; 82 lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */ 83 lua_Integer pos; /* where to insert new element */ 84 switch (lua_gettop(L)) { 85 case 2: { /* called with only 2 arguments */ 86 pos = e; /* insert new element at the end */ 87 break; 88 } 89 case 3: { 90 lua_Integer i; 91 pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ 92 luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); 93 for (i = e; i > pos; i--) { /* move up elements */ 94 (*ta.geti)(L, 1, i - 1); 95 (*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */ 96 } 97 break; 98 } 99 default: { 100 return luaL_error(L, "wrong number of arguments to 'insert'"); 101 } 102 } 103 (*ta.seti)(L, 1, pos); /* t[pos] = v */ 104 return 0; 105 } 106 107 108 static int tremove (lua_State *L) { 109 TabA ta; 110 lua_Integer size = aux_getn(L, 1, &ta); 111 lua_Integer pos = luaL_optinteger(L, 2, size); 112 if (pos != size) /* validate 'pos' if given */ 113 luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); 114 (*ta.geti)(L, 1, pos); /* result = t[pos] */ 115 for ( ; pos < size; pos++) { 116 (*ta.geti)(L, 1, pos + 1); 117 (*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */ 118 } 119 lua_pushnil(L); 120 (*ta.seti)(L, 1, pos); /* t[pos] = nil */ 121 return 1; 122 } 123 124 125 static int tmove (lua_State *L) { 126 TabA ta; 127 lua_Integer f = luaL_checkinteger(L, 2); 128 lua_Integer e = luaL_checkinteger(L, 3); 129 lua_Integer t = luaL_checkinteger(L, 4); 130 int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ 131 /* the following restriction avoids several problems with overflows */ 132 luaL_argcheck(L, f > 0, 2, "initial position must be positive"); 133 if (e >= f) { /* otherwise, nothing to move */ 134 lua_Integer n, i; 135 ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL) 136 ? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti) 137 : lua_geti; 138 ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL) 139 ? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti) 140 : lua_seti; 141 n = e - f + 1; /* number of elements to move */ 142 if (t > f) { 143 for (i = n - 1; i >= 0; i--) { 144 (*ta.geti)(L, 1, f + i); 145 (*ta.seti)(L, tt, t + i); 146 } 147 } 148 else { 149 for (i = 0; i < n; i++) { 150 (*ta.geti)(L, 1, f + i); 151 (*ta.seti)(L, tt, t + i); 152 } 153 } 154 } 155 lua_pushvalue(L, tt); /* return "to table" */ 156 return 1; 157 } 158 159 160 static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) { 161 (*ta->geti)(L, 1, i); 162 if (!lua_isstring(L, -1)) 163 luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", 164 luaL_typename(L, -1), i); 165 luaL_addvalue(b); 166 } 167 168 169 static int tconcat (lua_State *L) { 170 TabA ta; 171 luaL_Buffer b; 172 size_t lsep; 173 lua_Integer i, last; 174 const char *sep = luaL_optlstring(L, 2, "", &lsep); 175 checktab(L, 1, &ta); 176 i = luaL_optinteger(L, 3, 1); 177 last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1)); 178 luaL_buffinit(L, &b); 179 for (; i < last; i++) { 180 addfield(L, &b, &ta, i); 181 luaL_addlstring(&b, sep, lsep); 182 } 183 if (i == last) /* add last value (if interval was not empty) */ 184 addfield(L, &b, &ta, i); 185 luaL_pushresult(&b); 186 return 1; 187 } 188 189 190 /* 191 ** {====================================================== 192 ** Pack/unpack 193 ** ======================================================= 194 */ 195 196 static int pack (lua_State *L) { 197 int i; 198 int n = lua_gettop(L); /* number of elements to pack */ 199 lua_createtable(L, n, 1); /* create result table */ 200 lua_insert(L, 1); /* put it at index 1 */ 201 for (i = n; i >= 1; i--) /* assign elements */ 202 lua_rawseti(L, 1, i); 203 lua_pushinteger(L, n); 204 lua_setfield(L, 1, "n"); /* t.n = number of elements */ 205 return 1; /* return table */ 206 } 207 208 209 static int unpack (lua_State *L) { 210 TabA ta; 211 lua_Integer i, e; 212 lua_Unsigned n; 213 checktab(L, 1, &ta); 214 i = luaL_optinteger(L, 2, 1); 215 e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); 216 if (i > e) return 0; /* empty range */ 217 n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ 218 if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) 219 return luaL_error(L, "too many results to unpack"); 220 do { /* must have at least one element */ 221 (*ta.geti)(L, 1, i); /* push arg[i..e] */ 222 } while (i++ < e); 223 224 return (int)n; 225 } 226 227 /* }====================================================== */ 228 229 230 231 /* 232 ** {====================================================== 233 ** Quicksort 234 ** (based on 'Algorithms in MODULA-3', Robert Sedgewick; 235 ** Addison-Wesley, 1993.) 236 ** ======================================================= 237 */ 238 239 240 static void set2 (lua_State *L, TabA *ta, int i, int j) { 241 (*ta->seti)(L, 1, i); 242 (*ta->seti)(L, 1, j); 243 } 244 245 static int sort_comp (lua_State *L, int a, int b) { 246 if (!lua_isnil(L, 2)) { /* function? */ 247 int res; 248 lua_pushvalue(L, 2); 249 lua_pushvalue(L, a-1); /* -1 to compensate function */ 250 lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ 251 lua_call(L, 2, 1); 252 res = lua_toboolean(L, -1); 253 lua_pop(L, 1); 254 return res; 255 } 256 else /* a < b? */ 257 return lua_compare(L, a, b, LUA_OPLT); 258 } 259 260 static void auxsort (lua_State *L, TabA *ta, int l, int u) { 261 while (l < u) { /* for tail recursion */ 262 int i, j; 263 /* sort elements a[l], a[(l+u)/2] and a[u] */ 264 (*ta->geti)(L, 1, l); 265 (*ta->geti)(L, 1, u); 266 if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ 267 set2(L, ta, l, u); /* swap a[l] - a[u] */ 268 else 269 lua_pop(L, 2); 270 if (u-l == 1) break; /* only 2 elements */ 271 i = (l+u)/2; 272 (*ta->geti)(L, 1, i); 273 (*ta->geti)(L, 1, l); 274 if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */ 275 set2(L, ta, i, l); 276 else { 277 lua_pop(L, 1); /* remove a[l] */ 278 (*ta->geti)(L, 1, u); 279 if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */ 280 set2(L, ta, i, u); 281 else 282 lua_pop(L, 2); 283 } 284 if (u-l == 2) break; /* only 3 elements */ 285 (*ta->geti)(L, 1, i); /* Pivot */ 286 lua_pushvalue(L, -1); 287 (*ta->geti)(L, 1, u-1); 288 set2(L, ta, i, u-1); 289 /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ 290 i = l; j = u-1; 291 for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ 292 /* repeat ++i until a[i] >= P */ 293 while ((*ta->geti)(L, 1, ++i), sort_comp(L, -1, -2)) { 294 if (i>=u) luaL_error(L, "invalid order function for sorting"); 295 lua_pop(L, 1); /* remove a[i] */ 296 } 297 /* repeat --j until a[j] <= P */ 298 while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) { 299 if (j<=l) luaL_error(L, "invalid order function for sorting"); 300 lua_pop(L, 1); /* remove a[j] */ 301 } 302 if (j<i) { 303 lua_pop(L, 3); /* pop pivot, a[i], a[j] */ 304 break; 305 } 306 set2(L, ta, i, j); 307 } 308 (*ta->geti)(L, 1, u-1); 309 (*ta->geti)(L, 1, i); 310 set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */ 311 /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ 312 /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ 313 if (i-l < u-i) { 314 j=l; i=i-1; l=i+2; 315 } 316 else { 317 j=i+1; i=u; u=j-2; 318 } 319 auxsort(L, ta, j, i); /* call recursively the smaller one */ 320 } /* repeat the routine for the larger one */ 321 } 322 323 static int sort (lua_State *L) { 324 TabA ta; 325 int n = (int)aux_getn(L, 1, &ta); 326 luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */ 327 if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ 328 luaL_checktype(L, 2, LUA_TFUNCTION); 329 lua_settop(L, 2); /* make sure there are two arguments */ 330 auxsort(L, &ta, 1, n); 331 return 0; 332 } 333 334 /* }====================================================== */ 335 336 337 static const luaL_Reg tab_funcs[] = { 338 {"concat", tconcat}, 339 #if defined(LUA_COMPAT_MAXN) 340 {"maxn", maxn}, 341 #endif 342 {"insert", tinsert}, 343 {"pack", pack}, 344 {"unpack", unpack}, 345 {"remove", tremove}, 346 {"move", tmove}, 347 {"sort", sort}, 348 {NULL, NULL} 349 }; 350 351 352 LUAMOD_API int luaopen_table (lua_State *L) { 353 luaL_newlib(L, tab_funcs); 354 #if defined(LUA_COMPAT_UNPACK) 355 /* _G.unpack = table.unpack */ 356 lua_getfield(L, -1, "unpack"); 357 lua_setglobal(L, "unpack"); 358 #endif 359 return 1; 360 } 361 362