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