diff options
Diffstat (limited to 'ltable.c')
| -rw-r--r-- | ltable.c | 80 |
1 files changed, 65 insertions, 15 deletions
| @@ -40,6 +40,27 @@ | |||
| 40 | 40 | ||
| 41 | 41 | ||
| 42 | /* | 42 | /* |
| 43 | ** Only tables with hash parts larget than LIMFORLAST has a 'lastfree' | ||
| 44 | ** field that optimizes finding a free slot. Smaller tables do a | ||
| 45 | ** complete search when looking for a free slot. | ||
| 46 | */ | ||
| 47 | #define LLIMFORLAST 2 /* log2 of LIMTFORLAST */ | ||
| 48 | #define LIMFORLAST twoto(LLIMFORLAST) | ||
| 49 | |||
| 50 | /* | ||
| 51 | ** Union to store an int field ensuring that what follows it in | ||
| 52 | ** memory is properly aligned to store a TValue. | ||
| 53 | */ | ||
| 54 | typedef union { | ||
| 55 | int lastfree; | ||
| 56 | char padding[offsetof(struct { int i; TValue v; }, v)]; | ||
| 57 | } Limbox; | ||
| 58 | |||
| 59 | #define haslastfree(t) ((t)->lsizenode > LLIMFORLAST) | ||
| 60 | #define getlastfree(t) (&((cast(Limbox *, (t)->node) - 1)->lastfree)) | ||
| 61 | |||
| 62 | |||
| 63 | /* | ||
| 43 | ** MAXABITS is the largest integer such that MAXASIZE fits in an | 64 | ** MAXABITS is the largest integer such that MAXASIZE fits in an |
| 44 | ** unsigned int. | 65 | ** unsigned int. |
| 45 | */ | 66 | */ |
| @@ -367,8 +388,15 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
| 367 | 388 | ||
| 368 | 389 | ||
| 369 | static void freehash (lua_State *L, Table *t) { | 390 | static void freehash (lua_State *L, Table *t) { |
| 370 | if (!isdummy(t)) | 391 | if (!isdummy(t)) { |
| 371 | luaM_freearray(L, t->node, cast_sizet(sizenode(t))); | 392 | size_t bsize = sizenode(t) * sizeof(Node); /* 'node' size in bytes */ |
| 393 | char *arr = cast_charp(t->node); | ||
| 394 | if (haslastfree(t)) { | ||
| 395 | bsize += sizeof(Limbox); | ||
| 396 | arr -= sizeof(Limbox); | ||
| 397 | } | ||
| 398 | luaM_freearray(L, arr, bsize); | ||
| 399 | } | ||
| 372 | } | 400 | } |
| 373 | 401 | ||
| 374 | 402 | ||
| @@ -479,7 +507,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
| 479 | if (size == 0) { /* no elements to hash part? */ | 507 | if (size == 0) { /* no elements to hash part? */ |
| 480 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ | 508 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ |
| 481 | t->lsizenode = 0; | 509 | t->lsizenode = 0; |
| 482 | t->lastfree = NULL; /* signal that it is using dummy node */ | 510 | setdummy(t); /* signal that it is using dummy node */ |
| 483 | } | 511 | } |
| 484 | else { | 512 | else { |
| 485 | int i; | 513 | int i; |
| @@ -487,15 +515,22 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
| 487 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) | 515 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) |
| 488 | luaG_runerror(L, "table overflow"); | 516 | luaG_runerror(L, "table overflow"); |
| 489 | size = twoto(lsize); | 517 | size = twoto(lsize); |
| 490 | t->node = luaM_newvector(L, size, Node); | 518 | if (lsize <= LLIMFORLAST) /* no 'lastfree' field? */ |
| 519 | t->node = luaM_newvector(L, size, Node); | ||
| 520 | else { | ||
| 521 | size_t bsize = size * sizeof(Node) + sizeof(Limbox); | ||
| 522 | char *node = luaM_newblock(L, bsize); | ||
| 523 | t->node = cast(Node *, node + sizeof(Limbox)); | ||
| 524 | *getlastfree(t) = size; /* all positions are free */ | ||
| 525 | } | ||
| 526 | t->lsizenode = cast_byte(lsize); | ||
| 527 | setnodummy(t); | ||
| 491 | for (i = 0; i < cast_int(size); i++) { | 528 | for (i = 0; i < cast_int(size); i++) { |
| 492 | Node *n = gnode(t, i); | 529 | Node *n = gnode(t, i); |
| 493 | gnext(n) = 0; | 530 | gnext(n) = 0; |
| 494 | setnilkey(n); | 531 | setnilkey(n); |
| 495 | setempty(gval(n)); | 532 | setempty(gval(n)); |
| 496 | } | 533 | } |
| 497 | t->lsizenode = cast_byte(lsize); | ||
| 498 | t->lastfree = gnode(t, size); /* all positions are free */ | ||
| 499 | } | 534 | } |
| 500 | } | 535 | } |
| 501 | 536 | ||
| @@ -520,18 +555,21 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { | |||
| 520 | 555 | ||
| 521 | 556 | ||
| 522 | /* | 557 | /* |
| 523 | ** Exchange the hash part of 't1' and 't2'. | 558 | ** Exchange the hash part of 't1' and 't2'. (In 'flags', only the |
| 559 | ** dummy bit must be exchanged: The 'isrealasize' is not related | ||
| 560 | ** to the hash part, and the metamethod bits do not change during | ||
| 561 | ** a resize, so the "real" table can keep their values.) | ||
| 524 | */ | 562 | */ |
| 525 | static void exchangehashpart (Table *t1, Table *t2) { | 563 | static void exchangehashpart (Table *t1, Table *t2) { |
| 526 | lu_byte lsizenode = t1->lsizenode; | 564 | lu_byte lsizenode = t1->lsizenode; |
| 527 | Node *node = t1->node; | 565 | Node *node = t1->node; |
| 528 | Node *lastfree = t1->lastfree; | 566 | int bitdummy1 = t1->flags & BITDUMMY; |
| 529 | t1->lsizenode = t2->lsizenode; | 567 | t1->lsizenode = t2->lsizenode; |
| 530 | t1->node = t2->node; | 568 | t1->node = t2->node; |
| 531 | t1->lastfree = t2->lastfree; | 569 | t1->flags = (t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY); |
| 532 | t2->lsizenode = lsizenode; | 570 | t2->lsizenode = lsizenode; |
| 533 | t2->node = node; | 571 | t2->node = node; |
| 534 | t2->lastfree = lastfree; | 572 | t2->flags = (t2->flags & NOTBITDUMMY) | bitdummy1; |
| 535 | } | 573 | } |
| 536 | 574 | ||
| 537 | 575 | ||
| @@ -555,6 +593,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
| 555 | unsigned int oldasize = setlimittosize(t); | 593 | unsigned int oldasize = setlimittosize(t); |
| 556 | TValue *newarray; | 594 | TValue *newarray; |
| 557 | /* create new hash part with appropriate size into 'newt' */ | 595 | /* create new hash part with appropriate size into 'newt' */ |
| 596 | newt.flags = 0; | ||
| 558 | setnodevector(L, &newt, nhsize); | 597 | setnodevector(L, &newt, nhsize); |
| 559 | if (newasize < oldasize) { /* will array shrink? */ | 598 | if (newasize < oldasize) { /* will array shrink? */ |
| 560 | t->alimit = newasize; /* pretend array has new size... */ | 599 | t->alimit = newasize; /* pretend array has new size... */ |
| @@ -641,11 +680,22 @@ void luaH_free (lua_State *L, Table *t) { | |||
| 641 | 680 | ||
| 642 | 681 | ||
| 643 | static Node *getfreepos (Table *t) { | 682 | static Node *getfreepos (Table *t) { |
| 644 | if (!isdummy(t)) { | 683 | if (haslastfree(t)) { /* does it have 'lastfree' information? */ |
| 645 | while (t->lastfree > t->node) { | 684 | /* look for a spot before 'lastfree', updating 'lastfree' */ |
| 646 | t->lastfree--; | 685 | while (*getlastfree(t) > 0) { |
| 647 | if (keyisnil(t->lastfree)) | 686 | Node *free = gnode(t, --(*getlastfree(t))); |
| 648 | return t->lastfree; | 687 | if (keyisnil(free)) |
| 688 | return free; | ||
| 689 | } | ||
| 690 | } | ||
| 691 | else { /* no 'lastfree' information */ | ||
| 692 | if (!isdummy(t)) { | ||
| 693 | int i = sizenode(t); | ||
| 694 | while (i--) { /* do a linear search */ | ||
| 695 | Node *free = gnode(t, i); | ||
| 696 | if (keyisnil(free)) | ||
| 697 | return free; | ||
| 698 | } | ||
| 649 | } | 699 | } |
| 650 | } | 700 | } |
| 651 | return NULL; /* could not find a free place */ | 701 | return NULL; /* could not find a free place */ |
