diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-06-15 11:14:20 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-06-15 11:14:20 -0300 |
| commit | 6e600695f8398843a156ce02023f731c6d687ae8 (patch) | |
| tree | a3e8ef5078e24b5fbdfdfbd89e949bb6c078b90f | |
| parent | 06127927ffb4eb8459523f6c07bf8f22390c31b9 (diff) | |
| download | lua-6e600695f8398843a156ce02023f731c6d687ae8.tar.gz lua-6e600695f8398843a156ce02023f731c6d687ae8.tar.bz2 lua-6e600695f8398843a156ce02023f731c6d687ae8.zip | |
field 'sizearray' in struct 'Table' changed to 'alimit', which can
be used as a hint for '#t'
| -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 | ||
