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 */ |