Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/VM/src/ltablib.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
// This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details
3
#include "lualib.h"
4
5
#include "lapi.h"
6
#include "lnumutils.h"
7
#include "lstate.h"
8
#include "ltable.h"
9
#include "lstring.h"
10
#include "lgc.h"
11
#include "ldebug.h"
12
#include "lvm.h"
13
14
static int foreachi(lua_State* L)
15
{
16
luaL_checktype(L, 1, LUA_TTABLE);
17
luaL_checktype(L, 2, LUA_TFUNCTION);
18
int i;
19
int n = lua_objlen(L, 1);
20
for (i = 1; i <= n; i++)
21
{
22
lua_pushvalue(L, 2); // function
23
lua_pushinteger(L, i); // 1st argument
24
lua_rawgeti(L, 1, i); // 2nd argument
25
lua_call(L, 2, 1);
26
if (!lua_isnil(L, -1))
27
return 1;
28
lua_pop(L, 1); // remove nil result
29
}
30
return 0;
31
}
32
33
static int foreach (lua_State* L)
34
{
35
luaL_checktype(L, 1, LUA_TTABLE);
36
luaL_checktype(L, 2, LUA_TFUNCTION);
37
lua_pushnil(L); // first key
38
while (lua_next(L, 1))
39
{
40
lua_pushvalue(L, 2); // function
41
lua_pushvalue(L, -3); // key
42
lua_pushvalue(L, -3); // value
43
lua_call(L, 2, 1);
44
if (!lua_isnil(L, -1))
45
return 1;
46
lua_pop(L, 2); // remove value and result
47
}
48
return 0;
49
}
50
51
static int maxn(lua_State* L)
52
{
53
double max = 0;
54
luaL_checktype(L, 1, LUA_TTABLE);
55
56
LuaTable* t = hvalue(L->base);
57
58
for (int i = 0; i < t->sizearray; i++)
59
{
60
if (!ttisnil(&t->array[i]))
61
max = i + 1;
62
}
63
64
for (int i = 0; i < sizenode(t); i++)
65
{
66
LuaNode* n = gnode(t, i);
67
68
if (!ttisnil(gval(n)) && ttisnumber(gkey(n)))
69
{
70
double v = nvalue(gkey(n));
71
72
if (v > max)
73
max = v;
74
}
75
}
76
77
lua_pushnumber(L, max);
78
return 1;
79
}
80
81
static int getn(lua_State* L)
82
{
83
luaL_checktype(L, 1, LUA_TTABLE);
84
lua_pushinteger(L, lua_objlen(L, 1));
85
return 1;
86
}
87
88
static void moveelements(lua_State* L, int srct, int dstt, int f, int e, int t)
89
{
90
LuaTable* src = hvalue(L->base + (srct - 1));
91
LuaTable* dst = hvalue(L->base + (dstt - 1));
92
93
if (dst->readonly)
94
luaG_readonlyerror(L);
95
96
int n = e - f + 1; // number of elements to move
97
98
if (unsigned(f) - 1 < unsigned(src->sizearray) && unsigned(t) - 1 < unsigned(dst->sizearray) &&
99
unsigned(f) - 1 + unsigned(n) <= unsigned(src->sizearray) && unsigned(t) - 1 + unsigned(n) <= unsigned(dst->sizearray))
100
{
101
TValue* srcarray = src->array;
102
TValue* dstarray = dst->array;
103
104
if (t > e || t <= f || (dstt != srct && dst != src))
105
{
106
for (int i = 0; i < n; ++i)
107
{
108
TValue* s = &srcarray[f + i - 1];
109
TValue* d = &dstarray[t + i - 1];
110
setobj2t(L, d, s);
111
}
112
}
113
else
114
{
115
for (int i = n - 1; i >= 0; i--)
116
{
117
TValue* s = &srcarray[(f + i) - 1];
118
TValue* d = &dstarray[(t + i) - 1];
119
setobj2t(L, d, s);
120
}
121
}
122
123
luaC_barrierfast(L, dst);
124
}
125
else
126
{
127
if (t > e || t <= f || dst != src)
128
{
129
for (int i = 0; i < n; ++i)
130
{
131
lua_rawgeti(L, srct, f + i);
132
lua_rawseti(L, dstt, t + i);
133
}
134
}
135
else
136
{
137
for (int i = n - 1; i >= 0; i--)
138
{
139
lua_rawgeti(L, srct, f + i);
140
lua_rawseti(L, dstt, t + i);
141
}
142
}
143
}
144
}
145
146
static int tinsert(lua_State* L)
147
{
148
luaL_checktype(L, 1, LUA_TTABLE);
149
int n = lua_objlen(L, 1);
150
int pos; // where to insert new element
151
switch (lua_gettop(L))
152
{
153
case 2:
154
{ // called with only 2 arguments
155
pos = n + 1; // insert new element at the end
156
break;
157
}
158
case 3:
159
{
160
pos = luaL_checkinteger(L, 2); // 2nd argument is the position
161
162
// move up elements if necessary
163
if (1 <= pos && pos <= n)
164
moveelements(L, 1, 1, pos, n, pos + 1);
165
break;
166
}
167
default:
168
{
169
luaL_error(L, "wrong number of arguments to 'insert'");
170
}
171
}
172
lua_rawseti(L, 1, pos); // t[pos] = v
173
return 0;
174
}
175
176
static int tremove(lua_State* L)
177
{
178
luaL_checktype(L, 1, LUA_TTABLE);
179
int n = lua_objlen(L, 1);
180
int pos = luaL_optinteger(L, 2, n);
181
182
if (!(1 <= pos && pos <= n)) // position is outside bounds?
183
return 0; // nothing to remove
184
lua_rawgeti(L, 1, pos); // result = t[pos]
185
186
moveelements(L, 1, 1, pos + 1, n, pos);
187
188
lua_pushnil(L);
189
lua_rawseti(L, 1, n); // t[n] = nil
190
return 1;
191
}
192
193
/*
194
** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
195
** possible, copy in increasing order, which is better for rehashing.
196
** "possible" means destination after original range, or smaller
197
** than origin, or copying to another table.
198
*/
199
static int tmove(lua_State* L)
200
{
201
luaL_checktype(L, 1, LUA_TTABLE);
202
int f = luaL_checkinteger(L, 2);
203
int e = luaL_checkinteger(L, 3);
204
int t = luaL_checkinteger(L, 4);
205
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; // destination table
206
luaL_checktype(L, tt, LUA_TTABLE);
207
208
if (e >= f)
209
{ // otherwise, nothing to move
210
luaL_argcheck(L, f > 0 || e < INT_MAX + f, 3, "too many elements to move");
211
int n = e - f + 1; // number of elements to move
212
luaL_argcheck(L, t <= INT_MAX - n + 1, 4, "destination wrap around");
213
214
LuaTable* dst = hvalue(L->base + (tt - 1));
215
216
if (dst->readonly) // also checked in moveelements, but this blocks resizes of r/o tables
217
luaG_readonlyerror(L);
218
219
if (t > 0 && (t - 1) <= dst->sizearray && (t - 1 + n) > dst->sizearray)
220
{ // grow the destination table array
221
luaH_resizearray(L, dst, t - 1 + n);
222
}
223
224
moveelements(L, 1, tt, f, e, t);
225
}
226
lua_pushvalue(L, tt); // return destination table
227
return 1;
228
}
229
230
static void addfield(lua_State* L, luaL_Strbuf* b, int i, LuaTable* t)
231
{
232
if (t && unsigned(i - 1) < unsigned(t->sizearray) && ttisstring(&t->array[i - 1]))
233
{
234
TString* ts = tsvalue(&t->array[i - 1]);
235
luaL_addlstring(b, getstr(ts), ts->len);
236
}
237
else
238
{
239
int tt = lua_rawgeti(L, 1, i);
240
if (tt != LUA_TSTRING && tt != LUA_TNUMBER)
241
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", luaL_typename(L, -1), i);
242
luaL_addvalue(b);
243
}
244
}
245
246
static int tconcat(lua_State* L)
247
{
248
size_t lsep;
249
const char* sep = luaL_optlstring(L, 2, "", &lsep);
250
luaL_checktype(L, 1, LUA_TTABLE);
251
int i = luaL_optinteger(L, 3, 1);
252
int last = luaL_opt(L, luaL_checkinteger, 4, lua_objlen(L, 1));
253
254
LuaTable* t = hvalue(L->base);
255
256
luaL_Strbuf b;
257
luaL_buffinit(L, &b);
258
for (; i < last; i++)
259
{
260
addfield(L, &b, i, t);
261
if (lsep != 0)
262
luaL_addlstring(&b, sep, lsep);
263
}
264
if (i == last) // add last value (if interval was not empty)
265
addfield(L, &b, i, t);
266
luaL_pushresult(&b);
267
return 1;
268
}
269
270
static int tpack(lua_State* L)
271
{
272
int n = lua_gettop(L); // number of elements to pack
273
lua_createtable(L, n, 1); // create result table
274
275
LuaTable* t = hvalue(L->top - 1);
276
277
for (int i = 0; i < n; ++i)
278
{
279
TValue* e = &t->array[i];
280
setobj2t(L, e, L->base + i);
281
}
282
283
// t.n = number of elements
284
TValue* nv = luaH_setstr(L, t, luaS_newliteral(L, "n"));
285
setnvalue(nv, n);
286
287
return 1; // return table
288
}
289
290
static int tunpack(lua_State* L)
291
{
292
luaL_checktype(L, 1, LUA_TTABLE);
293
LuaTable* t = hvalue(L->base);
294
295
int i = luaL_optinteger(L, 2, 1);
296
int e = luaL_opt(L, luaL_checkinteger, 3, lua_objlen(L, 1));
297
if (i > e)
298
return 0; // empty range
299
unsigned n = (unsigned)e - i; // number of elements minus 1 (avoid overflows)
300
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
301
luaL_error(L, "too many results to unpack");
302
303
// fast-path: direct array-to-stack copy
304
if (i == 1 && int(n) <= t->sizearray)
305
{
306
for (i = 0; i < int(n); i++)
307
setobj2s(L, L->top + i, &t->array[i]);
308
L->top += n;
309
}
310
else
311
{
312
// push arg[i..e - 1] (to avoid overflows)
313
for (; i < e; i++)
314
lua_rawgeti(L, 1, i);
315
lua_rawgeti(L, 1, e); // push last element
316
}
317
return (int)n;
318
}
319
320
typedef int (*SortPredicate)(lua_State* L, const TValue* l, const TValue* r);
321
322
static int sort_func(lua_State* L, const TValue* l, const TValue* r)
323
{
324
LUAU_ASSERT(L->top == L->base + 2); // table, function
325
326
setobj2s(L, L->top, &L->base[1]);
327
setobj2s(L, L->top + 1, l);
328
setobj2s(L, L->top + 2, r);
329
L->top += 3; // safe because of LUA_MINSTACK guarantee
330
luaD_call(L, L->top - 3, 1);
331
L->top -= 1; // maintain stack depth
332
333
return !l_isfalse(L->top);
334
}
335
336
inline void sort_swap(lua_State* L, LuaTable* t, int i, int j)
337
{
338
TValue* arr = t->array;
339
int n = t->sizearray;
340
LUAU_ASSERT(unsigned(i) < unsigned(n) && unsigned(j) < unsigned(n)); // contract maintained in sort_less after predicate call
341
342
// no barrier required because both elements are in the array before and after the swap
343
TValue temp;
344
setobj2s(L, &temp, &arr[i]);
345
setobj2t(L, &arr[i], &arr[j]);
346
setobj2t(L, &arr[j], &temp);
347
}
348
349
inline int sort_less(lua_State* L, LuaTable* t, int i, int j, SortPredicate pred)
350
{
351
TValue* arr = t->array;
352
int n = t->sizearray;
353
LUAU_ASSERT(unsigned(i) < unsigned(n) && unsigned(j) < unsigned(n)); // contract maintained in sort_less after predicate call
354
355
int res = pred(L, &arr[i], &arr[j]);
356
357
// predicate call may resize the table, which is invalid
358
if (t->sizearray != n)
359
luaL_error(L, "table modified during sorting");
360
361
return res;
362
}
363
364
static void sort_siftheap(lua_State* L, LuaTable* t, int l, int u, SortPredicate pred, int root)
365
{
366
LUAU_ASSERT(l <= u);
367
int count = u - l + 1;
368
369
// process all elements with two children
370
while (root * 2 + 2 < count)
371
{
372
int left = root * 2 + 1, right = root * 2 + 2;
373
int next = root;
374
next = sort_less(L, t, l + next, l + left, pred) ? left : next;
375
next = sort_less(L, t, l + next, l + right, pred) ? right : next;
376
377
if (next == root)
378
break;
379
380
sort_swap(L, t, l + root, l + next);
381
root = next;
382
}
383
384
// process last element if it has just one child
385
int lastleft = root * 2 + 1;
386
if (lastleft == count - 1 && sort_less(L, t, l + root, l + lastleft, pred))
387
sort_swap(L, t, l + root, l + lastleft);
388
}
389
390
static void sort_heap(lua_State* L, LuaTable* t, int l, int u, SortPredicate pred)
391
{
392
LUAU_ASSERT(l <= u);
393
int count = u - l + 1;
394
395
for (int i = count / 2 - 1; i >= 0; --i)
396
sort_siftheap(L, t, l, u, pred, i);
397
398
for (int i = count - 1; i > 0; --i)
399
{
400
sort_swap(L, t, l, l + i);
401
sort_siftheap(L, t, l, l + i - 1, pred, 0);
402
}
403
}
404
405
static void sort_rec(lua_State* L, LuaTable* t, int l, int u, int limit, SortPredicate pred)
406
{
407
// sort range [l..u] (inclusive, 0-based)
408
while (l < u)
409
{
410
// if the limit has been reached, quick sort is going over the permitted nlogn complexity, so we fall back to heap sort
411
if (limit == 0)
412
return sort_heap(L, t, l, u, pred);
413
414
// sort elements a[l], a[(l+u)/2] and a[u]
415
// note: this simultaneously acts as a small sort and a median selector
416
if (sort_less(L, t, u, l, pred)) // a[u] < a[l]?
417
sort_swap(L, t, u, l); // swap a[l] - a[u]
418
if (u - l == 1)
419
break; // only 2 elements
420
int m = l + ((u - l) >> 1); // midpoint
421
if (sort_less(L, t, m, l, pred)) // a[m]<a[l]?
422
sort_swap(L, t, m, l);
423
else if (sort_less(L, t, u, m, pred)) // a[u]<a[m]?
424
sort_swap(L, t, m, u);
425
if (u - l == 2)
426
break; // only 3 elements
427
428
// here l, m, u are ordered; m will become the new pivot
429
int p = u - 1;
430
sort_swap(L, t, m, u - 1); // pivot is now (and always) at u-1
431
432
// a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2
433
int i = l;
434
int j = u - 1;
435
for (;;)
436
{ // invariant: a[l..i] <= P <= a[j..u]
437
// repeat ++i until a[i] >= P
438
while (sort_less(L, t, ++i, p, pred))
439
{
440
if (i >= u)
441
luaL_error(L, "invalid order function for sorting");
442
}
443
// repeat --j until a[j] <= P
444
while (sort_less(L, t, p, --j, pred))
445
{
446
if (j <= l)
447
luaL_error(L, "invalid order function for sorting");
448
}
449
if (j < i)
450
break;
451
sort_swap(L, t, i, j);
452
}
453
454
// swap pivot a[p] with a[i], which is the new midpoint
455
sort_swap(L, t, p, i);
456
457
// adjust limit to allow 1.5 log2N recursive steps
458
limit = (limit >> 1) + (limit >> 2);
459
460
// a[l..i-1] <= a[i] == P <= a[i+1..u]
461
// sort smaller half recursively; the larger half is sorted in the next loop iteration
462
if (i - l < u - i)
463
{
464
sort_rec(L, t, l, i - 1, limit, pred);
465
l = i + 1;
466
}
467
else
468
{
469
sort_rec(L, t, i + 1, u, limit, pred);
470
u = i - 1;
471
}
472
}
473
}
474
475
static int tsort(lua_State* L)
476
{
477
luaL_checktype(L, 1, LUA_TTABLE);
478
LuaTable* t = hvalue(L->base);
479
int n = luaH_getn(t);
480
if (t->readonly)
481
luaG_readonlyerror(L);
482
483
SortPredicate pred = luaV_lessthan;
484
if (!lua_isnoneornil(L, 2)) // is there a 2nd argument?
485
{
486
luaL_checktype(L, 2, LUA_TFUNCTION);
487
pred = sort_func;
488
}
489
lua_settop(L, 2); // make sure there are two arguments
490
491
if (n > 0)
492
sort_rec(L, t, 0, n - 1, n, pred);
493
return 0;
494
}
495
496
static int tcreate(lua_State* L)
497
{
498
int size = luaL_checkinteger(L, 1);
499
if (size < 0)
500
luaL_argerror(L, 1, "size out of range");
501
502
if (!lua_isnoneornil(L, 2))
503
{
504
lua_createtable(L, size, 0);
505
LuaTable* t = hvalue(L->top - 1);
506
507
StkId v = L->base + 1;
508
509
for (int i = 0; i < size; ++i)
510
{
511
TValue* e = &t->array[i];
512
setobj2t(L, e, v);
513
}
514
}
515
else
516
{
517
lua_createtable(L, size, 0);
518
}
519
520
return 1;
521
}
522
523
static int tfind(lua_State* L)
524
{
525
luaL_checktype(L, 1, LUA_TTABLE);
526
luaL_checkany(L, 2);
527
int init = luaL_optinteger(L, 3, 1);
528
if (init < 1)
529
luaL_argerror(L, 3, "index out of range");
530
531
LuaTable* t = hvalue(L->base);
532
533
for (int i = init;; ++i)
534
{
535
const TValue* e = luaH_getnum(t, i);
536
if (ttisnil(e))
537
break;
538
539
StkId v = L->base + 1;
540
541
if (equalobj(L, v, e))
542
{
543
lua_pushinteger(L, i);
544
return 1;
545
}
546
}
547
548
lua_pushnil(L);
549
return 1;
550
}
551
552
static int tclear(lua_State* L)
553
{
554
luaL_checktype(L, 1, LUA_TTABLE);
555
556
LuaTable* tt = hvalue(L->base);
557
if (tt->readonly)
558
luaG_readonlyerror(L);
559
560
luaH_clear(tt);
561
return 0;
562
}
563
564
static int tfreeze(lua_State* L)
565
{
566
luaL_checktype(L, 1, LUA_TTABLE);
567
luaL_argcheck(L, !lua_getreadonly(L, 1), 1, "table is already frozen");
568
luaL_argcheck(L, !luaL_getmetafield(L, 1, "__metatable"), 1, "table has a protected metatable");
569
570
lua_setreadonly(L, 1, true);
571
572
lua_pushvalue(L, 1);
573
return 1;
574
}
575
576
static int tisfrozen(lua_State* L)
577
{
578
luaL_checktype(L, 1, LUA_TTABLE);
579
580
lua_pushboolean(L, lua_getreadonly(L, 1));
581
return 1;
582
}
583
584
static int tclone(lua_State* L)
585
{
586
luaL_checktype(L, 1, LUA_TTABLE);
587
luaL_argcheck(L, !luaL_getmetafield(L, 1, "__metatable"), 1, "table has a protected metatable");
588
589
LuaTable* tt = luaH_clone(L, hvalue(L->base));
590
591
TValue v;
592
sethvalue(L, &v, tt);
593
luaA_pushobject(L, &v);
594
595
return 1;
596
}
597
598
static const luaL_Reg tab_funcs[] = {
599
{"concat", tconcat},
600
{"foreach", foreach},
601
{"foreachi", foreachi},
602
{"getn", getn},
603
{"maxn", maxn},
604
{"insert", tinsert},
605
{"remove", tremove},
606
{"sort", tsort},
607
{"pack", tpack},
608
{"unpack", tunpack},
609
{"move", tmove},
610
{"create", tcreate},
611
{"find", tfind},
612
{"clear", tclear},
613
{"freeze", tfreeze},
614
{"isfrozen", tisfrozen},
615
{"clone", tclone},
616
{NULL, NULL},
617
};
618
619
int luaopen_table(lua_State* L)
620
{
621
luaL_register(L, LUA_TABLIBNAME, tab_funcs);
622
623
// Lua 5.1 compat
624
lua_pushcfunction(L, tunpack, "unpack");
625
lua_setglobal(L, "unpack");
626
627
return 1;
628
}
629
630