diff options
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 36 |
1 files changed, 25 insertions, 11 deletions
@@ -273,7 +273,7 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) { | |||
273 | return t->alimit; /* this is the size */ | 273 | return t->alimit; /* this is the size */ |
274 | else { | 274 | else { |
275 | unsigned int size = t->alimit; | 275 | unsigned int size = t->alimit; |
276 | /* compute the smallest power of 2 not smaller than 'n' */ | 276 | /* compute the smallest power of 2 not smaller than 'size' */ |
277 | size |= (size >> 1); | 277 | size |= (size >> 1); |
278 | size |= (size >> 2); | 278 | size |= (size >> 2); |
279 | size |= (size >> 4); | 279 | size |= (size >> 4); |
@@ -772,22 +772,36 @@ static void luaH_newkey (lua_State *L, Table *t, const TValue *key, | |||
772 | 772 | ||
773 | /* | 773 | /* |
774 | ** Search function for integers. If integer is inside 'alimit', get it | 774 | ** Search function for integers. If integer is inside 'alimit', get it |
775 | ** directly from the array part. Otherwise, if 'alimit' is not equal to | 775 | ** directly from the array part. Otherwise, if 'alimit' is not |
776 | ** the real size of the array, key still can be in the array part. In | 776 | ** the real size of the array, the key still can be in the array part. |
777 | ** this case, try to avoid a call to 'luaH_realasize' when key is just | 777 | ** In this case, do the "Xmilia trick" to check whether 'key-1' is |
778 | ** one more than the limit (so that it can be incremented without | 778 | ** smaller than the real size. |
779 | ** changing the real size of the array). | 779 | ** The trick works as follow: let 'p' be an integer such that |
780 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
781 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
782 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
783 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
784 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
785 | ** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p', | ||
786 | ** therefore it will be larger or equal to 'alimit', and the check | ||
787 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than | ||
788 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
789 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
790 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
791 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
792 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
793 | ** if cannot be smaller than alimit. | ||
780 | */ | 794 | */ |
781 | const TValue *luaH_getint (Table *t, lua_Integer key) { | 795 | const TValue *luaH_getint (Table *t, lua_Integer key) { |
782 | if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ | 796 | lua_Unsigned alimit = t->alimit; |
797 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
783 | return &t->array[key - 1]; | 798 | return &t->array[key - 1]; |
784 | else if (!limitequalsasize(t) && /* key still may be in the array part? */ | 799 | else if (!isrealasize(t) && /* key still may be in the array part? */ |
785 | (l_castS2U(key) == t->alimit + 1 || | 800 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { |
786 | l_castS2U(key) - 1u < luaH_realasize(t))) { | ||
787 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | 801 | t->alimit = cast_uint(key); /* probably '#t' is here now */ |
788 | return &t->array[key - 1]; | 802 | return &t->array[key - 1]; |
789 | } | 803 | } |
790 | else { | 804 | else { /* key is not in the array part; check the hash */ |
791 | Node *n = hashint(t, key); | 805 | Node *n = hashint(t, key); |
792 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 806 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
793 | if (keyisinteger(n) && keyival(n) == key) | 807 | if (keyisinteger(n) && keyival(n) == key) |