Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/VM/src/ltable.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
4
/*
5
* Implementation of tables (aka arrays, objects, or hash tables).
6
*
7
* Tables keep the elements in two parts: an array part and a hash part.
8
* Integer keys >=1 are all candidates to be kept in the array part. The actual size of the array is the
9
* largest n such that at least half the slots between 0 and n are in use.
10
* Hash uses a mix of chained scatter table with Brent's variation.
11
*
12
* A main invariant of these tables is that, if an element is not in its main position (i.e. the original
13
* position that its hash gives to it), then the colliding element is in its own main position.
14
* Hence even when the load factor reaches 100%, performance remains good.
15
*
16
* Table keys can be arbitrary values unless they contain NaN. Keys are hashed and compared using raw equality,
17
* so even if the key is a userdata with an overridden __eq, it's not used during hash lookups.
18
*
19
* Each table has a "boundary", defined as the index k where t[k] ~= nil and t[k+1] == nil. The boundary can be
20
* computed using a binary search and can be adjusted when the table is modified; crucially, Luau enforces an
21
* invariant where the boundary must be in the array part - this enforces a consistent iteration order through the
22
* prefix of the table when using pairs(), and allows to implement algorithms that access elements in 1..#t range
23
* more efficiently.
24
*/
25
26
#include "ltable.h"
27
28
#include "lstate.h"
29
#include "ldebug.h"
30
#include "lgc.h"
31
#include "lmem.h"
32
#include "lnumutils.h"
33
34
#include <string.h>
35
36
// max size of both array and hash part is 2^MAXBITS
37
#define MAXBITS 26
38
#define MAXSIZE (1 << MAXBITS)
39
40
static_assert(offsetof(LuaNode, val) == 0, "Unexpected Node memory layout, pointer cast in gval2slot is incorrect");
41
42
// TKey is bitpacked for memory efficiency so we need to validate bit counts for worst case
43
static_assert(TKey{{NULL}, {0}, LUA_TDEADKEY, 0}.tt == LUA_TDEADKEY, "not enough bits for tt");
44
static_assert(TKey{{NULL}, {0}, LUA_TNIL, MAXSIZE - 1}.next == MAXSIZE - 1, "not enough bits for next");
45
static_assert(TKey{{NULL}, {0}, LUA_TNIL, -(MAXSIZE - 1)}.next == -(MAXSIZE - 1), "not enough bits for next");
46
47
// empty hash data points to dummynode so that we can always dereference it
48
const LuaNode luaH_dummynode = {
49
{{NULL}, {0}, LUA_TNIL}, // value
50
{{NULL}, {0}, LUA_TNIL, 0} // key
51
};
52
53
#define dummynode (&luaH_dummynode)
54
55
// hash is always reduced mod 2^k
56
#define hashpow2(t, n) (gnode(t, lmod((n), sizenode(t))))
57
58
#define hashstr(t, str) hashpow2(t, (str)->hash)
59
#define hashboolean(t, p) hashpow2(t, p)
60
61
static LuaNode* hashpointer(const LuaTable* t, const void* p)
62
{
63
// we discard the high 32-bit portion of the pointer on 64-bit platforms as it doesn't carry much entropy anyway
64
unsigned int h = unsigned(uintptr_t(p));
65
66
// MurmurHash3 32-bit finalizer
67
h ^= h >> 16;
68
h *= 0x85ebca6bu;
69
h ^= h >> 13;
70
h *= 0xc2b2ae35u;
71
h ^= h >> 16;
72
73
return hashpow2(t, h);
74
}
75
76
static LuaNode* hashnum(const LuaTable* t, double n)
77
{
78
static_assert(sizeof(double) == sizeof(unsigned int) * 2, "expected a 8-byte double");
79
unsigned int i[2];
80
memcpy(i, &n, sizeof(i));
81
82
// mask out sign bit to make sure -0 and 0 hash to the same value
83
uint32_t h1 = i[0];
84
uint32_t h2 = i[1] & 0x7fffffff;
85
86
// finalizer from MurmurHash64B
87
const uint32_t m = 0x5bd1e995;
88
89
h1 ^= h2 >> 18;
90
h1 *= m;
91
h2 ^= h1 >> 22;
92
h2 *= m;
93
h1 ^= h2 >> 17;
94
h1 *= m;
95
h2 ^= h1 >> 19;
96
h2 *= m;
97
98
// ... truncated to 32-bit output (normally hash is equal to (uint64_t(h1) << 32) | h2, but we only really need the lower 32-bit half)
99
return hashpow2(t, h2);
100
}
101
102
static LuaNode* hashint(const LuaTable* t, int64_t n)
103
{
104
static_assert(sizeof(n) == sizeof(unsigned int) * 2, "expected a 8-byte integer");
105
unsigned int i[2];
106
memcpy(i, &n, sizeof(i));
107
108
uint32_t h1 = i[0];
109
uint32_t h2 = i[1];
110
111
// finalizer from MurmurHash64B
112
const uint32_t m = 0x5bd1e995;
113
114
h1 ^= h2 >> 18;
115
h1 *= m;
116
h2 ^= h1 >> 22;
117
h2 *= m;
118
h1 ^= h2 >> 17;
119
h1 *= m;
120
h2 ^= h1 >> 19;
121
h2 *= m;
122
123
// ... truncated to 32-bit output (normally hash is equal to (uint64_t(h1) << 32) | h2, but we only really need the lower 32-bit half)
124
return hashpow2(t, h2);
125
}
126
127
static LuaNode* hashvec(const LuaTable* t, const float* v)
128
{
129
unsigned int i[LUA_VECTOR_SIZE];
130
memcpy(i, v, sizeof(i));
131
132
// convert -0 to 0 to make sure they hash to the same value
133
i[0] = (i[0] == 0x80000000) ? 0 : i[0];
134
i[1] = (i[1] == 0x80000000) ? 0 : i[1];
135
i[2] = (i[2] == 0x80000000) ? 0 : i[2];
136
137
// scramble bits to make sure that integer coordinates have entropy in lower bits
138
i[0] ^= i[0] >> 17;
139
i[1] ^= i[1] >> 17;
140
i[2] ^= i[2] >> 17;
141
142
// Optimized Spatial Hashing for Collision Detection of Deformable Objects
143
unsigned int h = (i[0] * 73856093) ^ (i[1] * 19349663) ^ (i[2] * 83492791);
144
145
#if LUA_VECTOR_SIZE == 4
146
i[3] = (i[3] == 0x80000000) ? 0 : i[3];
147
i[3] ^= i[3] >> 17;
148
h ^= i[3] * 39916801;
149
#endif
150
151
return hashpow2(t, h);
152
}
153
154
/*
155
** returns the `main' position of an element in a table (that is, the index
156
** of its hash value)
157
*/
158
static LuaNode* mainposition(const LuaTable* t, const TValue* key)
159
{
160
switch (ttype(key))
161
{
162
case LUA_TNUMBER:
163
return hashnum(t, nvalue(key));
164
case LUA_TINTEGER:
165
return hashint(t, lvalue(key));
166
case LUA_TVECTOR:
167
return hashvec(t, vvalue(key));
168
case LUA_TSTRING:
169
return hashstr(t, tsvalue(key));
170
case LUA_TBOOLEAN:
171
return hashboolean(t, bvalue(key));
172
case LUA_TLIGHTUSERDATA:
173
return hashpointer(t, pvalue(key));
174
default:
175
return hashpointer(t, gcvalue(key));
176
}
177
}
178
179
/*
180
** returns the index for `key' if `key' is an appropriate key to live in
181
** the array part of the table, -1 otherwise.
182
*/
183
static int arrayindex(double key)
184
{
185
int i;
186
luai_num2int(i, key);
187
188
return luai_numeq(cast_num(i), key) ? i : -1;
189
}
190
191
/*
192
** returns the index of a `key' for table traversals. First goes all
193
** elements in the array part, then elements in the hash part. The
194
** beginning of a traversal is signalled by -1.
195
*/
196
static int findindex(lua_State* L, LuaTable* t, StkId key)
197
{
198
int i;
199
if (ttisnil(key))
200
return -1; // first iteration
201
i = ttisnumber(key) ? arrayindex(nvalue(key)) : -1;
202
if (0 < i && i <= t->sizearray) // is `key' inside array part?
203
return i - 1; // yes; that's the index (corrected to C)
204
else
205
{
206
LuaNode* n = mainposition(t, key);
207
for (;;)
208
{ // check whether `key' is somewhere in the chain
209
// key may be dead already, but it is ok to use it in `next'
210
if (luaO_rawequalKey(gkey(n), key) || (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key)))
211
{
212
i = cast_int(n - gnode(t, 0)); // key index in hash table
213
// hash elements are numbered after array ones
214
return i + t->sizearray;
215
}
216
if (gnext(n) == 0)
217
break;
218
n += gnext(n);
219
}
220
luaG_runerror(L, "invalid key to 'next'"); // key not found
221
}
222
}
223
224
int luaH_next(lua_State* L, LuaTable* t, StkId key)
225
{
226
int i = findindex(L, t, key); // find original element
227
for (i++; i < t->sizearray; i++)
228
{ // try first array part
229
if (!ttisnil(&t->array[i]))
230
{ // a non-nil value?
231
setnvalue(key, cast_num(i + 1));
232
setobj2s(L, key + 1, &t->array[i]);
233
return 1;
234
}
235
}
236
for (i -= t->sizearray; i < sizenode(t); i++)
237
{ // then hash part
238
if (!ttisnil(gval(gnode(t, i))))
239
{ // a non-nil value?
240
getnodekey(L, key, gnode(t, i));
241
setobj2s(L, key + 1, gval(gnode(t, i)));
242
return 1;
243
}
244
}
245
return 0; // no more elements
246
}
247
248
/*
249
** {=============================================================
250
** Rehash
251
** ==============================================================
252
*/
253
254
#define maybesetaboundary(t, boundary) \
255
{ \
256
if (t->aboundary <= 0) \
257
t->aboundary = -int(boundary); \
258
}
259
260
#define getaboundary(t) (t->aboundary < 0 ? -t->aboundary : t->sizearray)
261
262
static int computesizes(int nums[], int* narray)
263
{
264
int i;
265
int twotoi; // 2^i
266
int a = 0; // number of elements smaller than 2^i
267
int na = 0; // number of elements to go to array part
268
int n = 0; // optimal size for array part
269
for (i = 0, twotoi = 1; twotoi / 2 < *narray; i++, twotoi *= 2)
270
{
271
if (nums[i] > 0)
272
{
273
a += nums[i];
274
if (a > twotoi / 2)
275
{ // more than half elements present?
276
n = twotoi; // optimal size (till now)
277
na = a; // all elements smaller than n will go to array part
278
}
279
}
280
if (a == *narray)
281
break; // all elements already counted
282
}
283
*narray = n;
284
LUAU_ASSERT(*narray / 2 <= na && na <= *narray);
285
return na;
286
}
287
288
static int countint(double key, int* nums)
289
{
290
int k = arrayindex(key);
291
if (0 < k && k <= MAXSIZE)
292
{ // is `key' an appropriate array index?
293
nums[ceillog2(k)]++; // count as such
294
return 1;
295
}
296
else
297
return 0;
298
}
299
300
static int numusearray(const LuaTable* t, int* nums)
301
{
302
int lg;
303
int ttlg; // 2^lg
304
int ause = 0; // summation of `nums'
305
int i = 1; // count to traverse all array keys
306
for (lg = 0, ttlg = 1; lg <= MAXBITS; lg++, ttlg *= 2)
307
{ // for each slice
308
int lc = 0; // counter
309
int lim = ttlg;
310
if (lim > t->sizearray)
311
{
312
lim = t->sizearray; // adjust upper limit
313
if (i > lim)
314
break; // no more elements to count
315
}
316
// count elements in range (2^(lg-1), 2^lg]
317
for (; i <= lim; i++)
318
{
319
if (!ttisnil(&t->array[i - 1]))
320
lc++;
321
}
322
nums[lg] += lc;
323
ause += lc;
324
}
325
return ause;
326
}
327
328
static int numusehash(const LuaTable* t, int* nums, int* pnasize)
329
{
330
int totaluse = 0; // total number of elements
331
int ause = 0; // summation of `nums'
332
int i = sizenode(t);
333
while (i--)
334
{
335
LuaNode* n = &t->node[i];
336
if (!ttisnil(gval(n)))
337
{
338
if (ttisnumber(gkey(n)))
339
ause += countint(nvalue(gkey(n)), nums);
340
totaluse++;
341
}
342
}
343
*pnasize += ause;
344
return totaluse;
345
}
346
347
static void setarrayvector(lua_State* L, LuaTable* t, int size)
348
{
349
if (size > MAXSIZE)
350
luaG_runerror(L, "table overflow");
351
luaM_reallocarray(L, t->array, t->sizearray, size, TValue, t->memcat);
352
TValue* array = t->array;
353
for (int i = t->sizearray; i < size; i++)
354
setnilvalue(&array[i]);
355
t->sizearray = size;
356
}
357
358
static void setnodevector(lua_State* L, LuaTable* t, int size)
359
{
360
int lsize;
361
if (size == 0)
362
{ // no elements to hash part?
363
t->node = cast_to(LuaNode*, dummynode); // use common `dummynode'
364
lsize = 0;
365
}
366
else
367
{
368
int i;
369
lsize = ceillog2(size);
370
if (lsize > MAXBITS)
371
luaG_runerror(L, "table overflow");
372
size = twoto(lsize);
373
t->node = luaM_newarray(L, size, LuaNode, t->memcat);
374
for (i = 0; i < size; i++)
375
{
376
LuaNode* n = gnode(t, i);
377
gnext(n) = 0;
378
setnilvalue(gkey(n));
379
setnilvalue(gval(n));
380
}
381
}
382
t->lsizenode = cast_byte(lsize);
383
t->nodemask8 = cast_byte((1 << lsize) - 1);
384
t->lastfree = size; // all positions are free
385
}
386
387
static TValue* newkey(lua_State* L, LuaTable* t, const TValue* key);
388
389
static TValue* arrayornewkey(lua_State* L, LuaTable* t, const TValue* key)
390
{
391
if (ttisnumber(key))
392
{
393
int k;
394
double n = nvalue(key);
395
luai_num2int(k, n);
396
if (luai_numeq(cast_num(k), n) && unsigned(k) - 1 < unsigned(t->sizearray))
397
return &t->array[k - 1];
398
}
399
400
return newkey(L, t, key);
401
}
402
403
static void resize(lua_State* L, LuaTable* t, int nasize, int nhsize)
404
{
405
if (nasize > MAXSIZE || nhsize > MAXSIZE)
406
luaG_runerror(L, "table overflow");
407
int oldasize = t->sizearray;
408
int oldhsize = t->lsizenode;
409
LuaNode* nold = t->node; // save old hash ...
410
if (nasize > oldasize) // array part must grow?
411
setarrayvector(L, t, nasize);
412
// create new hash part with appropriate size
413
setnodevector(L, t, nhsize);
414
// used for the migration check at the end
415
LuaNode* nnew = t->node;
416
if (nasize < oldasize)
417
{ // array part must shrink?
418
t->sizearray = nasize;
419
// re-insert elements from vanishing slice
420
for (int i = nasize; i < oldasize; i++)
421
{
422
if (!ttisnil(&t->array[i]))
423
{
424
TValue ok;
425
setnvalue(&ok, cast_num(i + 1));
426
setobjt2t(L, newkey(L, t, &ok), &t->array[i]);
427
}
428
}
429
// shrink array
430
luaM_reallocarray(L, t->array, oldasize, nasize, TValue, t->memcat);
431
}
432
// used for the migration check at the end
433
TValue* anew = t->array;
434
// re-insert elements from hash part
435
for (int i = twoto(oldhsize) - 1; i >= 0; i--)
436
{
437
LuaNode* old = nold + i;
438
if (!ttisnil(gval(old)))
439
{
440
TValue ok;
441
getnodekey(L, &ok, old);
442
setobjt2t(L, arrayornewkey(L, t, &ok), gval(old));
443
}
444
}
445
446
// make sure we haven't recursively rehashed during element migration
447
LUAU_ASSERT(nnew == t->node);
448
LUAU_ASSERT(anew == t->array);
449
450
if (nold != dummynode)
451
luaM_freearray(L, nold, twoto(oldhsize), LuaNode, t->memcat); // free old array
452
}
453
454
static int adjustasize(LuaTable* t, int size, const TValue* ek)
455
{
456
bool tbound = t->node != dummynode || size < t->sizearray;
457
int ekindex = ek && ttisnumber(ek) ? arrayindex(nvalue(ek)) : -1;
458
// move the array size up until the boundary is guaranteed to be inside the array part
459
while (size + 1 == ekindex || (tbound && !ttisnil(luaH_getnum(t, size + 1))))
460
size++;
461
return size;
462
}
463
464
void luaH_resizearray(lua_State* L, LuaTable* t, int nasize)
465
{
466
int nsize = (t->node == dummynode) ? 0 : sizenode(t);
467
int asize = adjustasize(t, nasize, NULL);
468
resize(L, t, asize, nsize);
469
}
470
471
void luaH_resizehash(lua_State* L, LuaTable* t, int nhsize)
472
{
473
resize(L, t, t->sizearray, nhsize);
474
}
475
476
static void rehash(lua_State* L, LuaTable* t, const TValue* ek)
477
{
478
int nums[MAXBITS + 1]; // nums[i] = number of keys between 2^(i-1) and 2^i
479
for (int i = 0; i <= MAXBITS; i++)
480
nums[i] = 0; // reset counts
481
int nasize = numusearray(t, nums); // count keys in array part
482
int totaluse = nasize; // all those keys are integer keys
483
totaluse += numusehash(t, nums, &nasize); // count keys in hash part
484
485
// count extra key
486
if (ttisnumber(ek))
487
nasize += countint(nvalue(ek), nums);
488
totaluse++;
489
490
// compute new size for array part
491
int na = computesizes(nums, &nasize);
492
int nh = totaluse - na;
493
494
// enforce the boundary invariant; for performance, only do hash lookups if we must
495
int nadjusted = adjustasize(t, nasize, ek);
496
497
// count how many extra elements belong to array part instead of hash part
498
int aextra = nadjusted - nasize;
499
500
if (aextra != 0)
501
{
502
// we no longer need to store those extra array elements in hash part
503
nh -= aextra;
504
505
// because hash nodes are twice as large as array nodes, the memory we saved for hash parts can be used by array part
506
// this follows the general sparse array part optimization where array is allocated when 50% occupation is reached
507
nasize = nadjusted + aextra;
508
509
// since the size was changed, it's again important to enforce the boundary invariant at the new size
510
nasize = adjustasize(t, nasize, ek);
511
}
512
513
// resize the table to new computed sizes
514
resize(L, t, nasize, nh);
515
}
516
517
/*
518
** }=============================================================
519
*/
520
521
LuaTable* luaH_new(lua_State* L, int narray, int nhash)
522
{
523
LuaTable* t = luaM_newgco(L, LuaTable, sizeof(LuaTable), L->activememcat);
524
luaC_init(L, t, LUA_TTABLE);
525
t->metatable = NULL;
526
t->tmcache = cast_byte(~0);
527
t->array = NULL;
528
t->sizearray = 0;
529
t->lastfree = 0;
530
t->lsizenode = 0;
531
t->readonly = 0;
532
t->safeenv = 0;
533
t->nodemask8 = 0;
534
t->node = cast_to(LuaNode*, dummynode);
535
if (narray > 0)
536
setarrayvector(L, t, narray);
537
if (nhash > 0)
538
setnodevector(L, t, nhash);
539
return t;
540
}
541
542
void luaH_free(lua_State* L, LuaTable* t, lua_Page* page)
543
{
544
if (t->node != dummynode)
545
luaM_freearray(L, t->node, sizenode(t), LuaNode, t->memcat);
546
if (t->array)
547
luaM_freearray(L, t->array, t->sizearray, TValue, t->memcat);
548
luaM_freegco(L, t, sizeof(LuaTable), t->memcat, page);
549
}
550
551
static LuaNode* getfreepos(LuaTable* t)
552
{
553
while (t->lastfree > 0)
554
{
555
t->lastfree--;
556
557
LuaNode* n = gnode(t, t->lastfree);
558
if (ttisnil(gkey(n)))
559
return n;
560
}
561
return NULL; // could not find a free place
562
}
563
564
/*
565
** inserts a new key into a hash table; first, check whether key's main
566
** position is free. If not, check whether colliding node is in its main
567
** position or not: if it is not, move colliding node to an empty place and
568
** put new key in its main position; otherwise (colliding node is in its main
569
** position), new key goes to an empty position.
570
*/
571
static TValue* newkey(lua_State* L, LuaTable* t, const TValue* key)
572
{
573
// enforce boundary invariant
574
if (ttisnumber(key) && nvalue(key) == t->sizearray + 1)
575
{
576
rehash(L, t, key); // grow table
577
578
// after rehash, numeric keys might be located in the new array part, but won't be found in the node part
579
return arrayornewkey(L, t, key);
580
}
581
582
LuaNode* mp = mainposition(t, key);
583
if (!ttisnil(gval(mp)) || mp == dummynode)
584
{
585
LuaNode* n = getfreepos(t); // get a free place
586
if (n == NULL)
587
{ // cannot find a free place?
588
rehash(L, t, key); // grow table
589
590
// after rehash, numeric keys might be located in the new array part, but won't be found in the node part
591
return arrayornewkey(L, t, key);
592
}
593
LUAU_ASSERT(n != dummynode);
594
TValue mk;
595
getnodekey(L, &mk, mp);
596
LuaNode* othern = mainposition(t, &mk);
597
if (othern != mp)
598
{ // is colliding node out of its main position?
599
// yes; move colliding node into free position
600
while (othern + gnext(othern) != mp)
601
othern += gnext(othern); // find previous
602
gnext(othern) = cast_int(n - othern); // redo the chain with `n' in place of `mp'
603
*n = *mp; // copy colliding node into free pos. (mp->next also goes)
604
if (gnext(mp) != 0)
605
{
606
gnext(n) += cast_int(mp - n); // correct 'next'
607
gnext(mp) = 0; // now 'mp' is free
608
}
609
setnilvalue(gval(mp));
610
}
611
else
612
{ // colliding node is in its own main position
613
// new node will go into free position
614
if (gnext(mp) != 0)
615
gnext(n) = cast_int((mp + gnext(mp)) - n); // chain new position
616
else
617
LUAU_ASSERT(gnext(n) == 0);
618
gnext(mp) = cast_int(n - mp);
619
mp = n;
620
}
621
}
622
setnodekey(L, mp, key);
623
luaC_barriert(L, t, key);
624
LUAU_ASSERT(ttisnil(gval(mp)));
625
return gval(mp);
626
}
627
628
/*
629
** search function for integers
630
*/
631
const TValue* luaH_getnum(LuaTable* t, int key)
632
{
633
// (1 <= key && key <= t->sizearray)
634
if (unsigned(key) - 1 < unsigned(t->sizearray))
635
return &t->array[key - 1];
636
else if (t->node != dummynode)
637
{
638
double nk = cast_num(key);
639
LuaNode* n = hashnum(t, nk);
640
for (;;)
641
{ // check whether `key' is somewhere in the chain
642
if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
643
return gval(n); // that's it
644
if (gnext(n) == 0)
645
break;
646
n += gnext(n);
647
}
648
return luaO_nilobject;
649
}
650
else
651
return luaO_nilobject;
652
}
653
654
/*
655
** search function for strings
656
*/
657
const TValue* luaH_getstr(LuaTable* t, TString* key)
658
{
659
LuaNode* n = hashstr(t, key);
660
for (;;)
661
{ // check whether `key' is somewhere in the chain
662
if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key)
663
return gval(n); // that's it
664
if (gnext(n) == 0)
665
break;
666
n += gnext(n);
667
}
668
return luaO_nilobject;
669
}
670
671
/*
672
** search function for lightuserdata
673
*/
674
const TValue* luaH_getp(LuaTable* t, void* key, int tag)
675
{
676
LuaNode* n = hashpointer(t, key);
677
for (;;)
678
{ // check whether `key' is somewhere in the chain
679
const TKey* nk = gkey(n);
680
if (ttislightuserdata(nk) && pvalue(nk) == key && lightuserdatatag(nk) == tag)
681
return gval(n); // that's it
682
if (gnext(n) == 0)
683
break;
684
n += gnext(n);
685
}
686
return luaO_nilobject;
687
}
688
689
/*
690
** main search function
691
*/
692
const TValue* luaH_get(LuaTable* t, const TValue* key)
693
{
694
switch (ttype(key))
695
{
696
case LUA_TNIL:
697
return luaO_nilobject;
698
case LUA_TSTRING:
699
return luaH_getstr(t, tsvalue(key));
700
case LUA_TNUMBER:
701
{
702
int k;
703
double n = nvalue(key);
704
luai_num2int(k, n);
705
if (luai_numeq(cast_num(k), nvalue(key))) // index is int?
706
return luaH_getnum(t, k); // use specialized version
707
LUAU_FALLTHROUGH; // else go through
708
}
709
default:
710
{
711
LuaNode* n = mainposition(t, key);
712
for (;;)
713
{ // check whether `key' is somewhere in the chain
714
if (luaO_rawequalKey(gkey(n), key))
715
return gval(n); // that's it
716
if (gnext(n) == 0)
717
break;
718
n += gnext(n);
719
}
720
return luaO_nilobject;
721
}
722
}
723
}
724
725
TValue* luaH_set(lua_State* L, LuaTable* t, const TValue* key)
726
{
727
const TValue* p = luaH_get(t, key);
728
invalidateTMcache(t);
729
if (p != luaO_nilobject)
730
return cast_to(TValue*, p);
731
else
732
return luaH_newkey(L, t, key);
733
}
734
735
TValue* luaH_newkey(lua_State* L, LuaTable* t, const TValue* key)
736
{
737
if (ttisnil(key))
738
luaG_runerror(L, "table index is nil");
739
else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
740
luaG_runerror(L, "table index is NaN");
741
else if (ttisvector(key) && luai_vecisnan(vvalue(key)))
742
luaG_runerror(L, "table index contains NaN");
743
return newkey(L, t, key);
744
}
745
746
TValue* luaH_setnum(lua_State* L, LuaTable* t, int key)
747
{
748
// (1 <= key && key <= t->sizearray)
749
if (unsigned(key) - 1 < unsigned(t->sizearray))
750
return &t->array[key - 1];
751
// hash fallback
752
const TValue* p = luaH_getnum(t, key);
753
if (p != luaO_nilobject)
754
return cast_to(TValue*, p);
755
else
756
{
757
TValue k;
758
setnvalue(&k, cast_num(key));
759
return newkey(L, t, &k);
760
}
761
}
762
763
TValue* luaH_setstr(lua_State* L, LuaTable* t, TString* key)
764
{
765
const TValue* p = luaH_getstr(t, key);
766
invalidateTMcache(t);
767
if (p != luaO_nilobject)
768
return cast_to(TValue*, p);
769
else
770
{
771
TValue k;
772
setsvalue(L, &k, key);
773
return newkey(L, t, &k);
774
}
775
}
776
777
TValue* luaH_setp(lua_State* L, LuaTable* t, void* key, int tag)
778
{
779
const TValue* p = luaH_getp(t, key, tag);
780
if (p != luaO_nilobject)
781
return cast_to(TValue*, p);
782
else
783
{
784
TValue k;
785
setpvalue(&k, key, tag);
786
return newkey(L, t, &k);
787
}
788
}
789
790
static int updateaboundary(LuaTable* t, int boundary)
791
{
792
if (boundary < t->sizearray && ttisnil(&t->array[boundary - 1]))
793
{
794
if (boundary >= 2 && !ttisnil(&t->array[boundary - 2]))
795
{
796
maybesetaboundary(t, boundary - 1);
797
return boundary - 1;
798
}
799
}
800
else if (boundary + 1 < t->sizearray && !ttisnil(&t->array[boundary]) && ttisnil(&t->array[boundary + 1]))
801
{
802
maybesetaboundary(t, boundary + 1);
803
return boundary + 1;
804
}
805
806
return 0;
807
}
808
809
/*
810
** Try to find a boundary in table `t'. A `boundary' is an integer index
811
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
812
*/
813
int luaH_getn(LuaTable* t)
814
{
815
int boundary = getaboundary(t);
816
817
if (boundary > 0)
818
{
819
if (!ttisnil(&t->array[t->sizearray - 1]) && t->node == dummynode)
820
return t->sizearray; // fast-path: the end of the array in `t' already refers to a boundary
821
if (boundary < t->sizearray && !ttisnil(&t->array[boundary - 1]) && ttisnil(&t->array[boundary]))
822
return boundary; // fast-path: boundary already refers to a boundary in `t'
823
824
int foundboundary = updateaboundary(t, boundary);
825
if (foundboundary > 0)
826
return foundboundary;
827
}
828
829
int j = t->sizearray;
830
831
if (j > 0 && ttisnil(&t->array[j - 1]))
832
{
833
// "branchless" binary search from Array Layouts for Comparison-Based Searching, Paul Khuong, Pat Morin, 2017.
834
// note that clang is cmov-shy on cmovs around memory operands, so it will compile this to a branchy loop.
835
TValue* base = t->array;
836
int rest = j;
837
while (int half = rest >> 1)
838
{
839
base = ttisnil(&base[half]) ? base : base + half;
840
rest -= half;
841
}
842
int boundary = !ttisnil(base) + int(base - t->array);
843
maybesetaboundary(t, boundary);
844
return boundary;
845
}
846
else
847
{
848
// validate boundary invariant
849
LUAU_ASSERT(t->node == dummynode || ttisnil(luaH_getnum(t, j + 1)));
850
return j;
851
}
852
}
853
854
LuaTable* luaH_clone(lua_State* L, LuaTable* tt)
855
{
856
LuaTable* t = luaM_newgco(L, LuaTable, sizeof(LuaTable), L->activememcat);
857
luaC_init(L, t, LUA_TTABLE);
858
t->metatable = tt->metatable;
859
t->tmcache = tt->tmcache;
860
t->array = NULL;
861
t->sizearray = 0;
862
t->lsizenode = 0;
863
t->nodemask8 = 0;
864
t->readonly = 0;
865
t->safeenv = 0;
866
t->node = cast_to(LuaNode*, dummynode);
867
t->lastfree = 0;
868
869
if (tt->sizearray)
870
{
871
t->array = luaM_newarray(L, tt->sizearray, TValue, t->memcat);
872
maybesetaboundary(t, getaboundary(tt));
873
t->sizearray = tt->sizearray;
874
875
memcpy(t->array, tt->array, t->sizearray * sizeof(TValue));
876
}
877
878
if (tt->node != dummynode)
879
{
880
int size = 1 << tt->lsizenode;
881
t->node = luaM_newarray(L, size, LuaNode, t->memcat);
882
t->lsizenode = tt->lsizenode;
883
t->nodemask8 = tt->nodemask8;
884
memcpy(t->node, tt->node, size * sizeof(LuaNode));
885
t->lastfree = tt->lastfree;
886
}
887
888
return t;
889
}
890
891
void luaH_clear(LuaTable* tt)
892
{
893
// clear array part
894
for (int i = 0; i < tt->sizearray; ++i)
895
{
896
setnilvalue(&tt->array[i]);
897
}
898
899
maybesetaboundary(tt, 0);
900
901
// clear hash part
902
if (tt->node != dummynode)
903
{
904
int size = sizenode(tt);
905
tt->lastfree = size;
906
for (int i = 0; i < size; ++i)
907
{
908
LuaNode* n = gnode(tt, i);
909
setnilvalue(gkey(n));
910
setnilvalue(gval(n));
911
gnext(n) = 0;
912
}
913
}
914
915
// back to empty -> no tag methods present
916
tt->tmcache = cast_byte(~0);
917
}
918
919