aboutsummaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltable.c')
-rw-r--r--ltable.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/ltable.c b/ltable.c
index 8db26bdc..103478fb 100644
--- a/ltable.c
+++ b/ltable.c
@@ -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*/
781const TValue *luaH_getint (Table *t, lua_Integer key) { 795const 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)