diff options
-rw-r--r-- | lgc.c | 15 | ||||
-rw-r--r-- | lobject.h | 17 | ||||
-rw-r--r-- | ltable.c | 197 | ||||
-rw-r--r-- | ltable.h | 3 | ||||
-rw-r--r-- | ltests.c | 15 | ||||
-rw-r--r-- | lvm.c | 4 | ||||
-rw-r--r-- | lvm.h | 4 |
7 files changed, 201 insertions, 54 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.252 2018/02/26 13:35:03 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.253 2018/03/16 14:22:09 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -398,7 +398,7 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
398 | Node *n, *limit = gnodelast(h); | 398 | Node *n, *limit = gnodelast(h); |
399 | /* if there is array part, assume it may have white values (it is not | 399 | /* if there is array part, assume it may have white values (it is not |
400 | worth traversing it now just to check) */ | 400 | worth traversing it now just to check) */ |
401 | int hasclears = (h->sizearray > 0); | 401 | int hasclears = (h->alimit > 0); |
402 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 402 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
403 | if (isempty(gval(n))) /* entry is empty? */ | 403 | if (isempty(gval(n))) /* entry is empty? */ |
404 | clearkey(n); /* clear its key */ | 404 | clearkey(n); /* clear its key */ |
@@ -433,8 +433,9 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
433 | int hasww = 0; /* true if table has entry "white-key -> white-value" */ | 433 | int hasww = 0; /* true if table has entry "white-key -> white-value" */ |
434 | Node *n, *limit = gnodelast(h); | 434 | Node *n, *limit = gnodelast(h); |
435 | unsigned int i; | 435 | unsigned int i; |
436 | unsigned int asize = luaH_realasize(h); | ||
436 | /* traverse array part */ | 437 | /* traverse array part */ |
437 | for (i = 0; i < h->sizearray; i++) { | 438 | for (i = 0; i < asize; i++) { |
438 | if (valiswhite(&h->array[i])) { | 439 | if (valiswhite(&h->array[i])) { |
439 | marked = 1; | 440 | marked = 1; |
440 | reallymarkobject(g, gcvalue(&h->array[i])); | 441 | reallymarkobject(g, gcvalue(&h->array[i])); |
@@ -472,7 +473,8 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
472 | static void traversestrongtable (global_State *g, Table *h) { | 473 | static void traversestrongtable (global_State *g, Table *h) { |
473 | Node *n, *limit = gnodelast(h); | 474 | Node *n, *limit = gnodelast(h); |
474 | unsigned int i; | 475 | unsigned int i; |
475 | for (i = 0; i < h->sizearray; i++) /* traverse array part */ | 476 | unsigned int asize = luaH_realasize(h); |
477 | for (i = 0; i < asize; i++) /* traverse array part */ | ||
476 | markvalue(g, &h->array[i]); | 478 | markvalue(g, &h->array[i]); |
477 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 479 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
478 | if (isempty(gval(n))) /* entry is empty? */ | 480 | if (isempty(gval(n))) /* entry is empty? */ |
@@ -508,7 +510,7 @@ static lu_mem traversetable (global_State *g, Table *h) { | |||
508 | } | 510 | } |
509 | else /* not weak */ | 511 | else /* not weak */ |
510 | traversestrongtable(g, h); | 512 | traversestrongtable(g, h); |
511 | return 1 + h->sizearray + 2 * allocsizenode(h); | 513 | return 1 + h->alimit + 2 * allocsizenode(h); |
512 | } | 514 | } |
513 | 515 | ||
514 | 516 | ||
@@ -719,7 +721,8 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
719 | Table *h = gco2t(l); | 721 | Table *h = gco2t(l); |
720 | Node *n, *limit = gnodelast(h); | 722 | Node *n, *limit = gnodelast(h); |
721 | unsigned int i; | 723 | unsigned int i; |
722 | for (i = 0; i < h->sizearray; i++) { | 724 | unsigned int asize = luaH_realasize(h); |
725 | for (i = 0; i < asize; i++) { | ||
723 | TValue *o = &h->array[i]; | 726 | TValue *o = &h->array[i]; |
724 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ | 727 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ |
725 | setempty(o); /* remove entry */ | 728 | setempty(o); /* remove entry */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 2.143 2018/06/01 16:51:34 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.144 2018/06/01 17:40:38 roberto Exp roberto $ |
3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -669,11 +669,24 @@ typedef union Node { | |||
669 | (void)L; checkliveness(L,io_); } | 669 | (void)L; checkliveness(L,io_); } |
670 | 670 | ||
671 | 671 | ||
672 | /* | ||
673 | ** About 'alimit': if 'isrealasize(t)' is true, then 'alimit' is the | ||
674 | ** real size of 'array'. Otherwise, the real size of 'array' is the | ||
675 | ** smallest power of two not smaller than 'alimit' (or zero iff 'alimit' | ||
676 | ** is zero); 'alimit' is then used as a hint for #t. | ||
677 | */ | ||
678 | |||
679 | #define BITRAS (1 << 7) | ||
680 | #define isrealasize(t) (!((t)->marked & BITRAS)) | ||
681 | #define setrealasize(t) ((t)->marked &= cast_byte(~BITRAS)) | ||
682 | #define setnorealasize(t) ((t)->marked |= BITRAS) | ||
683 | |||
684 | |||
672 | typedef struct Table { | 685 | typedef struct Table { |
673 | CommonHeader; | 686 | CommonHeader; |
674 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ | 687 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ |
675 | lu_byte lsizenode; /* log2 of size of 'node' array */ | 688 | lu_byte lsizenode; /* log2 of size of 'node' array */ |
676 | unsigned int sizearray; /* size of 'array' array */ | 689 | unsigned int alimit; /* "limit" of 'array' array */ |
677 | TValue *array; /* array part */ | 690 | TValue *array; /* array part */ |
678 | Node *node; | 691 | Node *node; |
679 | Node *lastfree; /* any free position is before this position */ | 692 | Node *lastfree; /* any free position is before this position */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 2.137 2018/05/30 14:25:52 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 2.138 2018/06/01 16:51:34 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -193,6 +193,59 @@ static int equalkey (const TValue *k1, const Node *n2) { | |||
193 | 193 | ||
194 | 194 | ||
195 | /* | 195 | /* |
196 | ** True if value of 'alimit' is equal to the real size of the array | ||
197 | ** part of table 't'. (Otherwise, the array part must be larger than | ||
198 | ** 'alimit'.) | ||
199 | */ | ||
200 | #define limitequalsasize(t) (isrealasize(t) || ispow2((t)->alimit)) | ||
201 | |||
202 | |||
203 | /* | ||
204 | ** Returns the real size of the 'array' array | ||
205 | */ | ||
206 | LUAI_FUNC unsigned int luaH_realasize (const Table *t) { | ||
207 | if (limitequalsasize(t)) | ||
208 | return t->alimit; /* this is the size */ | ||
209 | else { | ||
210 | unsigned int size = t->alimit; | ||
211 | /* compute the smallest power of 2 not smaller than 'n' */ | ||
212 | size |= (size >> 1); | ||
213 | size |= (size >> 2); | ||
214 | size |= (size >> 4); | ||
215 | size |= (size >> 8); | ||
216 | size |= (size >> 16); | ||
217 | #if (INT_MAX >> 30 >> 1) > 0 | ||
218 | size |= (size >> 32); /* int has more than 32 bits */ | ||
219 | #endif | ||
220 | size++; | ||
221 | lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size); | ||
222 | return size; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | |||
227 | /* | ||
228 | ** Check whether real size of the array is a power of 2. | ||
229 | ** (If it is not, 'alimit' cannot be changed to any other value | ||
230 | ** without changing the real size.) | ||
231 | */ | ||
232 | static int ispow2realasize (const Table *t) { | ||
233 | return (!isrealasize(t) || ispow2(t->alimit)); | ||
234 | } | ||
235 | |||
236 | |||
237 | static unsigned int setlimittosize (Table *t) { | ||
238 | t->alimit = luaH_realasize(t); | ||
239 | setrealasize(t); | ||
240 | return t->alimit; | ||
241 | } | ||
242 | |||
243 | |||
244 | #define limitasasize(t) check_exp(isrealasize(t), t->alimit) | ||
245 | |||
246 | |||
247 | |||
248 | /* | ||
196 | ** "Generic" get version. (Not that generic: not valid for integers, | 249 | ** "Generic" get version. (Not that generic: not valid for integers, |
197 | ** which may be in array part, nor for floats with integral values.) | 250 | ** which may be in array part, nor for floats with integral values.) |
198 | */ | 251 | */ |
@@ -228,11 +281,12 @@ static unsigned int arrayindex (lua_Integer k) { | |||
228 | ** elements in the array part, then elements in the hash part. The | 281 | ** elements in the array part, then elements in the hash part. The |
229 | ** beginning of a traversal is signaled by 0. | 282 | ** beginning of a traversal is signaled by 0. |
230 | */ | 283 | */ |
231 | static unsigned int findindex (lua_State *L, Table *t, TValue *key) { | 284 | static unsigned int findindex (lua_State *L, Table *t, TValue *key, |
285 | unsigned int asize) { | ||
232 | unsigned int i; | 286 | unsigned int i; |
233 | if (ttisnil(key)) return 0; /* first iteration */ | 287 | if (ttisnil(key)) return 0; /* first iteration */ |
234 | i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; | 288 | i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; |
235 | if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ | 289 | if (i != 0 && i <= asize) /* is 'key' inside array part? */ |
236 | return i; /* yes; that's the index */ | 290 | return i; /* yes; that's the index */ |
237 | else { | 291 | else { |
238 | const TValue *n = getgeneric(t, key); | 292 | const TValue *n = getgeneric(t, key); |
@@ -240,21 +294,22 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key) { | |||
240 | luaG_runerror(L, "invalid key to 'next'"); /* key not found */ | 294 | luaG_runerror(L, "invalid key to 'next'"); /* key not found */ |
241 | i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ | 295 | i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ |
242 | /* hash elements are numbered after array ones */ | 296 | /* hash elements are numbered after array ones */ |
243 | return (i + 1) + t->sizearray; | 297 | return (i + 1) + asize; |
244 | } | 298 | } |
245 | } | 299 | } |
246 | 300 | ||
247 | 301 | ||
248 | int luaH_next (lua_State *L, Table *t, StkId key) { | 302 | int luaH_next (lua_State *L, Table *t, StkId key) { |
249 | unsigned int i = findindex(L, t, s2v(key)); /* find original element */ | 303 | unsigned int asize = luaH_realasize(t); |
250 | for (; i < t->sizearray; i++) { /* try first array part */ | 304 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ |
305 | for (; i < asize; i++) { /* try first array part */ | ||
251 | if (!isempty(&t->array[i])) { /* a non-empty entry? */ | 306 | if (!isempty(&t->array[i])) { /* a non-empty entry? */ |
252 | setivalue(s2v(key), i + 1); | 307 | setivalue(s2v(key), i + 1); |
253 | setobj2s(L, key + 1, &t->array[i]); | 308 | setobj2s(L, key + 1, &t->array[i]); |
254 | return 1; | 309 | return 1; |
255 | } | 310 | } |
256 | } | 311 | } |
257 | for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ | 312 | for (i -= asize; cast_int(i) < sizenode(t); i++) { /* hash part */ |
258 | if (!isempty(gval(gnode(t, i)))) { /* a non-empty entry? */ | 313 | if (!isempty(gval(gnode(t, i)))) { /* a non-empty entry? */ |
259 | Node *n = gnode(t, i); | 314 | Node *n = gnode(t, i); |
260 | getnodekey(L, s2v(key), n); | 315 | getnodekey(L, s2v(key), n); |
@@ -329,12 +384,13 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) { | |||
329 | unsigned int ttlg; /* 2^lg */ | 384 | unsigned int ttlg; /* 2^lg */ |
330 | unsigned int ause = 0; /* summation of 'nums' */ | 385 | unsigned int ause = 0; /* summation of 'nums' */ |
331 | unsigned int i = 1; /* count to traverse all array keys */ | 386 | unsigned int i = 1; /* count to traverse all array keys */ |
387 | unsigned int asize = limitasasize(t); /* real array size */ | ||
332 | /* traverse each slice */ | 388 | /* traverse each slice */ |
333 | for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { | 389 | for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { |
334 | unsigned int lc = 0; /* counter */ | 390 | unsigned int lc = 0; /* counter */ |
335 | unsigned int lim = ttlg; | 391 | unsigned int lim = ttlg; |
336 | if (lim > t->sizearray) { | 392 | if (lim > asize) { |
337 | lim = t->sizearray; /* adjust upper limit */ | 393 | lim = asize; /* adjust upper limit */ |
338 | if (i > lim) | 394 | if (i > lim) |
339 | break; /* no more elements to count */ | 395 | break; /* no more elements to count */ |
340 | } | 396 | } |
@@ -451,19 +507,19 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
451 | unsigned int nhsize) { | 507 | unsigned int nhsize) { |
452 | unsigned int i; | 508 | unsigned int i; |
453 | Table newt; /* to keep the new hash part */ | 509 | Table newt; /* to keep the new hash part */ |
454 | unsigned int oldasize = t->sizearray; | 510 | unsigned int oldasize = setlimittosize(t); |
455 | TValue *newarray; | 511 | TValue *newarray; |
456 | /* create new hash part with appropriate size into 'newt' */ | 512 | /* create new hash part with appropriate size into 'newt' */ |
457 | setnodevector(L, &newt, nhsize); | 513 | setnodevector(L, &newt, nhsize); |
458 | if (newasize < oldasize) { /* will array shrink? */ | 514 | if (newasize < oldasize) { /* will array shrink? */ |
459 | t->sizearray = newasize; /* pretend array has new size... */ | 515 | t->alimit = newasize; /* pretend array has new size... */ |
460 | exchangehashpart(t, &newt); /* and new hash */ | 516 | exchangehashpart(t, &newt); /* and new hash */ |
461 | /* re-insert into the new hash the elements from vanishing slice */ | 517 | /* re-insert into the new hash the elements from vanishing slice */ |
462 | for (i = newasize; i < oldasize; i++) { | 518 | for (i = newasize; i < oldasize; i++) { |
463 | if (!isempty(&t->array[i])) | 519 | if (!isempty(&t->array[i])) |
464 | luaH_setint(L, t, i + 1, &t->array[i]); | 520 | luaH_setint(L, t, i + 1, &t->array[i]); |
465 | } | 521 | } |
466 | t->sizearray = oldasize; /* restore current size... */ | 522 | t->alimit = oldasize; /* restore current size... */ |
467 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ | 523 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ |
468 | } | 524 | } |
469 | /* allocate new array */ | 525 | /* allocate new array */ |
@@ -475,7 +531,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
475 | /* allocation ok; initialize new part of the array */ | 531 | /* allocation ok; initialize new part of the array */ |
476 | exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */ | 532 | exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */ |
477 | t->array = newarray; /* set new array part */ | 533 | t->array = newarray; /* set new array part */ |
478 | t->sizearray = newasize; | 534 | t->alimit = newasize; |
479 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ | 535 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ |
480 | setempty(&t->array[i]); | 536 | setempty(&t->array[i]); |
481 | /* re-insert elements from old hash part into new parts */ | 537 | /* re-insert elements from old hash part into new parts */ |
@@ -499,6 +555,7 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { | |||
499 | int i; | 555 | int i; |
500 | int totaluse; | 556 | int totaluse; |
501 | for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ | 557 | for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ |
558 | setlimittosize(t); | ||
502 | na = numusearray(t, nums); /* count keys in array part */ | 559 | na = numusearray(t, nums); /* count keys in array part */ |
503 | totaluse = na; /* all those keys are integer keys */ | 560 | totaluse = na; /* all those keys are integer keys */ |
504 | totaluse += numusehash(t, nums, &na); /* count keys in hash part */ | 561 | totaluse += numusehash(t, nums, &na); /* count keys in hash part */ |
@@ -525,7 +582,7 @@ Table *luaH_new (lua_State *L) { | |||
525 | t->metatable = NULL; | 582 | t->metatable = NULL; |
526 | t->flags = cast_byte(~0); | 583 | t->flags = cast_byte(~0); |
527 | t->array = NULL; | 584 | t->array = NULL; |
528 | t->sizearray = 0; | 585 | t->alimit = 0; |
529 | setnodevector(L, t, 0); | 586 | setnodevector(L, t, 0); |
530 | return t; | 587 | return t; |
531 | } | 588 | } |
@@ -533,7 +590,7 @@ Table *luaH_new (lua_State *L) { | |||
533 | 590 | ||
534 | void luaH_free (lua_State *L, Table *t) { | 591 | void luaH_free (lua_State *L, Table *t) { |
535 | freehash(L, t); | 592 | freehash(L, t); |
536 | luaM_freearray(L, t->array, t->sizearray); | 593 | luaM_freearray(L, t->array, luaH_realasize(t)); |
537 | luaM_free(L, t); | 594 | luaM_free(L, t); |
538 | } | 595 | } |
539 | 596 | ||
@@ -613,12 +670,21 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { | |||
613 | 670 | ||
614 | 671 | ||
615 | /* | 672 | /* |
616 | ** search function for integers | 673 | ** Search function for integers. If integer is inside 'alimit', get it |
674 | ** directly from the array part. Otherwise, if 'alimit' is not equal to | ||
675 | ** the real size of the array, key still can be in the array part. In | ||
676 | ** this case, try to avoid a call to 'luaH_realasize' when key is just | ||
677 | ** one more than the limit (so that it can be incremented without | ||
678 | ** changing the real size of the array). | ||
617 | */ | 679 | */ |
618 | const TValue *luaH_getint (Table *t, lua_Integer key) { | 680 | const TValue *luaH_getint (Table *t, lua_Integer key) { |
619 | /* (1 <= key && key <= t->sizearray) */ | 681 | if (l_castS2U(key) - 1u < t->alimit) /* (1 <= key && key <= t->alimit)? */ |
620 | if (l_castS2U(key) - 1u < t->sizearray) | ||
621 | return &t->array[key - 1]; | 682 | return &t->array[key - 1]; |
683 | else if (!limitequalsasize(t) && /* key still may be in the array part? */ | ||
684 | (key == t->alimit + 1 || l_castS2U(key) - 1u < luaH_realasize(t))) { | ||
685 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
686 | return &t->array[key - 1]; | ||
687 | } | ||
622 | else { | 688 | else { |
623 | Node *n = hashint(t, key); | 689 | Node *n = hashint(t, key); |
624 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 690 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
@@ -749,33 +815,92 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { | |||
749 | } | 815 | } |
750 | 816 | ||
751 | 817 | ||
818 | static unsigned int binsearch (const TValue *array, unsigned int i, | ||
819 | unsigned int j) { | ||
820 | while (j - i > 1u) { /* binary search */ | ||
821 | unsigned int m = (i + j) / 2; | ||
822 | if (isempty(&array[m - 1])) j = m; | ||
823 | else i = m; | ||
824 | } | ||
825 | return i; | ||
826 | } | ||
827 | |||
828 | |||
752 | /* | 829 | /* |
753 | ** Try to find a boundary in table 't'. (A 'boundary' is an integer index | 830 | ** Try to find a boundary in table 't'. (A 'boundary' is an integer index |
754 | ** such that t[i] is present and t[i+1] is absent, or 0 if t[1] is absent | 831 | ** such that t[i] is present and t[i+1] is absent, or 0 if t[1] is absent |
755 | ** and 'maxinteger' if t[maxinteger] is present.) | 832 | ** and 'maxinteger' if t[maxinteger] is present.) |
756 | ** First, try the array part: if there is an array part and its last | 833 | ** (In the next explanation, we use Lua indices, that is, with base 1. |
757 | ** element is absent, there must be a boundary there; a binary search | 834 | ** The code itself uses base 0 when indexing the array part of the table.) |
758 | ** finds that boundary. Otherwise, if the hash part is empty or does not | 835 | ** The code starts with 'limit', a position in the array part that may |
759 | ** contain 'j + 1', 'j' is a boundary. Otherwize, call 'hash_search' | 836 | ** be a boundary. |
760 | ** to find a boundary in the hash part. | 837 | ** (1) If 't[limit]' is empty, there must be a boundary before it. |
838 | ** As a common case (e.g., after 't[#t]=nil'), check whether 'hint-1' | ||
839 | ** is present. If so, it is a boundary. Otherwise, do a binary search | ||
840 | ** between 0 and limit to find a boundary. In both cases, try to | ||
841 | ** use this boundary as the new 'limit', as a hint for the next call. | ||
842 | ** (2) If 't[limit]' is not empty and the array has more elements | ||
843 | ** after 'limit', try to find a boundary there. Again, try first | ||
844 | ** the special case (which should be quite frequent) where 'limit+1' | ||
845 | ** is empty, so that 'limit' is a boundary. Otherwise, check the | ||
846 | ** last element of the array part (set it as a new limit). If it is empty, | ||
847 | ** there must be a boundary between the old limit (present) and the new | ||
848 | ** limit (absent), which is found with a binary search. (This boundary | ||
849 | ** always can be a new limit.) | ||
850 | ** (3) The last case is when there are no elements in the array part | ||
851 | ** (limit == 0) or its last element (the new limit) is present. | ||
852 | ** In this case, must check the hash part. If there is no hash part, | ||
853 | ** the boundary is 0. Otherwise, if 'limit+1' is absent, 'limit' is | ||
854 | ** a boundary. Finally, if 'limit+1' is present, call 'hash_search' | ||
855 | ** to find a boundary in the hash part of the table. (In those | ||
856 | ** cases, the boundary is not inside the array part, and therefore | ||
857 | ** cannot be used as a new limit.) | ||
761 | */ | 858 | */ |
762 | lua_Unsigned luaH_getn (Table *t) { | 859 | lua_Unsigned luaH_getn (Table *t) { |
763 | unsigned int j = t->sizearray; | 860 | unsigned int limit = t->alimit; |
764 | if (j > 0 && isempty(&t->array[j - 1])) { | 861 | if (limit > 0 && isempty(&t->array[limit - 1])) { |
765 | unsigned int i = 0; | 862 | /* (1) there must be a boundary before 'limit' */ |
766 | while (j - i > 1u) { /* binary search */ | 863 | if (limit >= 2 && !isempty(&t->array[limit - 2])) { |
767 | unsigned int m = (i + j) / 2; | 864 | /* 'limit - 1' is a boundary; can it be a new limit? */ |
768 | if (isempty(&t->array[m - 1])) j = m; | 865 | if (ispow2realasize(t) && !ispow2(limit - 1)) { |
769 | else i = m; | 866 | t->alimit = limit - 1; |
867 | setnorealasize(t); | ||
868 | } | ||
869 | return limit - 1; | ||
870 | } | ||
871 | else { /* must search for a boundary in [0, limit] */ | ||
872 | unsigned int boundary = binsearch(t->array, 0, limit); | ||
873 | /* can this boundary represent the real size of the array? */ | ||
874 | if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { | ||
875 | t->alimit = boundary; /* use it as the new limit */ | ||
876 | setnorealasize(t); | ||
877 | } | ||
878 | return boundary; | ||
770 | } | 879 | } |
771 | return i; | ||
772 | } | 880 | } |
773 | else { /* 'j' is zero or present in table */ | 881 | /* 'limit' is zero or present in table */ |
774 | if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, j + 1)))) | 882 | if (!limitequalsasize(t)) { |
775 | return j; /* 'j + 1' is absent... */ | 883 | /* (2) 'limit' > 0 and array has more elements after 'limit' */ |
776 | else /* 'j + 1' is also present */ | 884 | if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ |
777 | return hash_search(t, j); | 885 | return limit; /* this is the boundary */ |
886 | /* else, try last element in the array */ | ||
887 | limit = luaH_realasize(t); | ||
888 | if (isempty(&t->array[limit - 1])) { /* empty? */ | ||
889 | /* there must be a boundary in the array after old limit, | ||
890 | and it must be a valid new limit */ | ||
891 | unsigned int boundary = binsearch(t->array, t->alimit, limit); | ||
892 | t->alimit = boundary; | ||
893 | return boundary; | ||
894 | } | ||
895 | /* else, new limit is present in the table; check the hash part */ | ||
778 | } | 896 | } |
897 | /* (3) 'limit' is the last element and either is zero or present in table */ | ||
898 | lua_assert(limit == luaH_realasize(t) && | ||
899 | (limit == 0 || !isempty(&t->array[limit - 1]))); | ||
900 | if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1)))) | ||
901 | return limit; /* 'limit + 1' is absent... */ | ||
902 | else /* 'limit + 1' is also present */ | ||
903 | return hash_search(t, limit); | ||
779 | } | 904 | } |
780 | 905 | ||
781 | 906 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.h,v 2.26 2018/02/23 13:13:31 roberto Exp roberto $ | 2 | ** $Id: ltable.h,v 2.27 2018/06/01 16:51:34 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -45,6 +45,7 @@ LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); | |||
45 | LUAI_FUNC void luaH_free (lua_State *L, Table *t); | 45 | LUAI_FUNC void luaH_free (lua_State *L, Table *t); |
46 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); | 46 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); |
47 | LUAI_FUNC lua_Unsigned luaH_getn (Table *t); | 47 | LUAI_FUNC lua_Unsigned luaH_getn (Table *t); |
48 | LUAI_FUNC unsigned int luaH_realasize (const Table *t); | ||
48 | 49 | ||
49 | 50 | ||
50 | #if defined(LUA_DEBUG) | 51 | #if defined(LUA_DEBUG) |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltests.c,v 2.243 2018/03/09 19:24:45 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.244 2018/06/11 14:19:50 roberto Exp roberto $ |
3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -248,10 +248,11 @@ static void checkvalref (global_State *g, GCObject *f, const TValue *t) { | |||
248 | 248 | ||
249 | static void checktable (global_State *g, Table *h) { | 249 | static void checktable (global_State *g, Table *h) { |
250 | unsigned int i; | 250 | unsigned int i; |
251 | unsigned int asize = luaH_realasize(h); | ||
251 | Node *n, *limit = gnode(h, sizenode(h)); | 252 | Node *n, *limit = gnode(h, sizenode(h)); |
252 | GCObject *hgc = obj2gco(h); | 253 | GCObject *hgc = obj2gco(h); |
253 | checkobjref(g, hgc, h->metatable); | 254 | checkobjref(g, hgc, h->metatable); |
254 | for (i = 0; i < h->sizearray; i++) | 255 | for (i = 0; i < asize; i++) |
255 | checkvalref(g, hgc, &h->array[i]); | 256 | checkvalref(g, hgc, &h->array[i]); |
256 | for (n = gnode(h, 0); n < limit; n++) { | 257 | for (n = gnode(h, 0); n < limit; n++) { |
257 | if (!isempty(gval(n))) { | 258 | if (!isempty(gval(n))) { |
@@ -810,19 +811,23 @@ static int stacklevel (lua_State *L) { | |||
810 | static int table_query (lua_State *L) { | 811 | static int table_query (lua_State *L) { |
811 | const Table *t; | 812 | const Table *t; |
812 | int i = cast_int(luaL_optinteger(L, 2, -1)); | 813 | int i = cast_int(luaL_optinteger(L, 2, -1)); |
814 | unsigned int asize; | ||
813 | luaL_checktype(L, 1, LUA_TTABLE); | 815 | luaL_checktype(L, 1, LUA_TTABLE); |
814 | t = hvalue(obj_at(L, 1)); | 816 | t = hvalue(obj_at(L, 1)); |
817 | asize = luaH_realasize(t); | ||
815 | if (i == -1) { | 818 | if (i == -1) { |
816 | lua_pushinteger(L, t->sizearray); | 819 | lua_pushinteger(L, asize); |
817 | lua_pushinteger(L, allocsizenode(t)); | 820 | lua_pushinteger(L, allocsizenode(t)); |
818 | lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node); | 821 | lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node); |
822 | lua_pushinteger(L, t->alimit); | ||
823 | return 4; | ||
819 | } | 824 | } |
820 | else if ((unsigned int)i < t->sizearray) { | 825 | else if ((unsigned int)i < asize) { |
821 | lua_pushinteger(L, i); | 826 | lua_pushinteger(L, i); |
822 | pushobject(L, &t->array[i]); | 827 | pushobject(L, &t->array[i]); |
823 | lua_pushnil(L); | 828 | lua_pushnil(L); |
824 | } | 829 | } |
825 | else if ((i -= t->sizearray) < sizenode(t)) { | 830 | else if ((i -= asize) < sizenode(t)) { |
826 | TValue k; | 831 | TValue k; |
827 | getnodekey(L, &k, gnode(t, i)); | 832 | getnodekey(L, &k, gnode(t, i)); |
828 | if (!isempty(gval(gnode(t, i))) || | 833 | if (!isempty(gval(gnode(t, i))) || |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.356 2018/05/30 14:25:52 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.357 2018/06/01 16:51:34 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -1766,7 +1766,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1766 | } | 1766 | } |
1767 | h = hvalue(s2v(ra)); | 1767 | h = hvalue(s2v(ra)); |
1768 | last = ((c-1)*LFIELDS_PER_FLUSH) + n; | 1768 | last = ((c-1)*LFIELDS_PER_FLUSH) + n; |
1769 | if (last > h->sizearray) /* needs more space? */ | 1769 | if (last > luaH_realasize(h)) /* needs more space? */ |
1770 | luaH_resizearray(L, h, last); /* preallocate it at once */ | 1770 | luaH_resizearray(L, h, last); /* preallocate it at once */ |
1771 | for (; n > 0; n--) { | 1771 | for (; n > 0; n--) { |
1772 | TValue *val = s2v(ra + n); | 1772 | TValue *val = s2v(ra + n); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.h,v 2.50 2018/02/21 12:54:26 roberto Exp roberto $ | 2 | ** $Id: lvm.h,v 2.51 2018/02/23 13:13:31 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -84,7 +84,7 @@ | |||
84 | #define luaV_fastgeti(L,t,k,slot) \ | 84 | #define luaV_fastgeti(L,t,k,slot) \ |
85 | (!ttistable(t) \ | 85 | (!ttistable(t) \ |
86 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ | 86 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ |
87 | : (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \ | 87 | : (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \ |
88 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ | 88 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ |
89 | !isempty(slot))) /* result not empty? */ | 89 | !isempty(slot))) /* result not empty? */ |
90 | 90 | ||