diff options
Diffstat (limited to '')
-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 | */ |
@@ -370,8 +391,15 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
370 | 391 | ||
371 | 392 | ||
372 | static void freehash (lua_State *L, Table *t) { | 393 | static void freehash (lua_State *L, Table *t) { |
373 | if (!isdummy(t)) | 394 | if (!isdummy(t)) { |
374 | luaM_freearray(L, t->node, cast_sizet(sizenode(t))); | 395 | size_t bsize = sizenode(t) * sizeof(Node); /* 'node' size in bytes */ |
396 | char *arr = cast_charp(t->node); | ||
397 | if (haslastfree(t)) { | ||
398 | bsize += sizeof(Limbox); | ||
399 | arr -= sizeof(Limbox); | ||
400 | } | ||
401 | luaM_freearray(L, arr, bsize); | ||
402 | } | ||
375 | } | 403 | } |
376 | 404 | ||
377 | 405 | ||
@@ -550,7 +578,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
550 | if (size == 0) { /* no elements to hash part? */ | 578 | if (size == 0) { /* no elements to hash part? */ |
551 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ | 579 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ |
552 | t->lsizenode = 0; | 580 | t->lsizenode = 0; |
553 | t->lastfree = NULL; /* signal that it is using dummy node */ | 581 | setdummy(t); /* signal that it is using dummy node */ |
554 | } | 582 | } |
555 | else { | 583 | else { |
556 | int i; | 584 | int i; |
@@ -558,15 +586,22 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
558 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) | 586 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) |
559 | luaG_runerror(L, "table overflow"); | 587 | luaG_runerror(L, "table overflow"); |
560 | size = twoto(lsize); | 588 | size = twoto(lsize); |
561 | t->node = luaM_newvector(L, size, Node); | 589 | if (lsize <= LLIMFORLAST) /* no 'lastfree' field? */ |
590 | t->node = luaM_newvector(L, size, Node); | ||
591 | else { | ||
592 | size_t bsize = size * sizeof(Node) + sizeof(Limbox); | ||
593 | char *node = luaM_newblock(L, bsize); | ||
594 | t->node = cast(Node *, node + sizeof(Limbox)); | ||
595 | *getlastfree(t) = size; /* all positions are free */ | ||
596 | } | ||
597 | t->lsizenode = cast_byte(lsize); | ||
598 | setnodummy(t); | ||
562 | for (i = 0; i < cast_int(size); i++) { | 599 | for (i = 0; i < cast_int(size); i++) { |
563 | Node *n = gnode(t, i); | 600 | Node *n = gnode(t, i); |
564 | gnext(n) = 0; | 601 | gnext(n) = 0; |
565 | setnilkey(n); | 602 | setnilkey(n); |
566 | setempty(gval(n)); | 603 | setempty(gval(n)); |
567 | } | 604 | } |
568 | t->lsizenode = cast_byte(lsize); | ||
569 | t->lastfree = gnode(t, size); /* all positions are free */ | ||
570 | } | 605 | } |
571 | } | 606 | } |
572 | 607 | ||
@@ -591,18 +626,21 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { | |||
591 | 626 | ||
592 | 627 | ||
593 | /* | 628 | /* |
594 | ** Exchange the hash part of 't1' and 't2'. | 629 | ** Exchange the hash part of 't1' and 't2'. (In 'flags', only the |
630 | ** dummy bit must be exchanged: The 'isrealasize' is not related | ||
631 | ** to the hash part, and the metamethod bits do not change during | ||
632 | ** a resize, so the "real" table can keep their values.) | ||
595 | */ | 633 | */ |
596 | static void exchangehashpart (Table *t1, Table *t2) { | 634 | static void exchangehashpart (Table *t1, Table *t2) { |
597 | lu_byte lsizenode = t1->lsizenode; | 635 | lu_byte lsizenode = t1->lsizenode; |
598 | Node *node = t1->node; | 636 | Node *node = t1->node; |
599 | Node *lastfree = t1->lastfree; | 637 | int bitdummy1 = t1->flags & BITDUMMY; |
600 | t1->lsizenode = t2->lsizenode; | 638 | t1->lsizenode = t2->lsizenode; |
601 | t1->node = t2->node; | 639 | t1->node = t2->node; |
602 | t1->lastfree = t2->lastfree; | 640 | t1->flags = (t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY); |
603 | t2->lsizenode = lsizenode; | 641 | t2->lsizenode = lsizenode; |
604 | t2->node = node; | 642 | t2->node = node; |
605 | t2->lastfree = lastfree; | 643 | t2->flags = (t2->flags & NOTBITDUMMY) | bitdummy1; |
606 | } | 644 | } |
607 | 645 | ||
608 | 646 | ||
@@ -626,6 +664,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
626 | unsigned int oldasize = setlimittosize(t); | 664 | unsigned int oldasize = setlimittosize(t); |
627 | ArrayCell *newarray; | 665 | ArrayCell *newarray; |
628 | /* create new hash part with appropriate size into 'newt' */ | 666 | /* create new hash part with appropriate size into 'newt' */ |
667 | newt.flags = 0; | ||
629 | setnodevector(L, &newt, nhsize); | 668 | setnodevector(L, &newt, nhsize); |
630 | if (newasize < oldasize) { /* will array shrink? */ | 669 | if (newasize < oldasize) { /* will array shrink? */ |
631 | t->alimit = newasize; /* pretend array has new size... */ | 670 | t->alimit = newasize; /* pretend array has new size... */ |
@@ -717,11 +756,22 @@ void luaH_free (lua_State *L, Table *t) { | |||
717 | 756 | ||
718 | 757 | ||
719 | static Node *getfreepos (Table *t) { | 758 | static Node *getfreepos (Table *t) { |
720 | if (!isdummy(t)) { | 759 | if (haslastfree(t)) { /* does it have 'lastfree' information? */ |
721 | while (t->lastfree > t->node) { | 760 | /* look for a spot before 'lastfree', updating 'lastfree' */ |
722 | t->lastfree--; | 761 | while (*getlastfree(t) > 0) { |
723 | if (keyisnil(t->lastfree)) | 762 | Node *free = gnode(t, --(*getlastfree(t))); |
724 | return t->lastfree; | 763 | if (keyisnil(free)) |
764 | return free; | ||
765 | } | ||
766 | } | ||
767 | else { /* no 'lastfree' information */ | ||
768 | if (!isdummy(t)) { | ||
769 | int i = sizenode(t); | ||
770 | while (i--) { /* do a linear search */ | ||
771 | Node *free = gnode(t, i); | ||
772 | if (keyisnil(free)) | ||
773 | return free; | ||
774 | } | ||
725 | } | 775 | } |
726 | } | 776 | } |
727 | return NULL; /* could not find a free place */ | 777 | return NULL; /* could not find a free place */ |