diff options
author | Philipp Janda <siffiejoe@gmx.net> | 2015-01-20 01:15:00 +0100 |
---|---|---|
committer | Philipp Janda <siffiejoe@gmx.net> | 2015-01-20 01:15:00 +0100 |
commit | e52c3c4e7af665acd23e63fd3ae85f2c8ae87e49 (patch) | |
tree | 3067b1a8578cdddd9bdb1f5b5a3dba13c51a80fc /ltablib.c | |
parent | 489cd678823e0981ff2e4d2544b84094ed23c587 (diff) | |
download | lua-compat-5.3-e52c3c4e7af665acd23e63fd3ae85f2c8ae87e49.tar.gz lua-compat-5.3-e52c3c4e7af665acd23e63fd3ae85f2c8ae87e49.tar.bz2 lua-compat-5.3-e52c3c4e7af665acd23e63fd3ae85f2c8ae87e49.zip |
use table library from Lua 5.3 sources if available
Diffstat (limited to 'ltablib.c')
-rw-r--r-- | ltablib.c | 357 |
1 files changed, 357 insertions, 0 deletions
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 | |||