diff options
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 116 |
1 files changed, 60 insertions, 56 deletions
@@ -350,9 +350,10 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
350 | unsigned int asize = luaH_realasize(t); | 350 | unsigned int asize = luaH_realasize(t); |
351 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ | 351 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ |
352 | for (; i < asize; i++) { /* try first array part */ | 352 | for (; i < asize; i++) { /* try first array part */ |
353 | if (!isempty(&t->array[i])) { /* a non-empty entry? */ | 353 | int tag = *getArrTag(t, i + 1); |
354 | if (!tagisempty(tag)) { /* a non-empty entry? */ | ||
354 | setivalue(s2v(key), i + 1); | 355 | setivalue(s2v(key), i + 1); |
355 | setobj2s(L, key + 1, &t->array[i]); | 356 | farr2val(t, i + 1, tag, s2v(key + 1)); |
356 | return 1; | 357 | return 1; |
357 | } | 358 | } |
358 | } | 359 | } |
@@ -375,6 +376,41 @@ static void freehash (lua_State *L, Table *t) { | |||
375 | 376 | ||
376 | 377 | ||
377 | /* | 378 | /* |
379 | ** Check whether an integer key is in the array part. If 'alimit' is | ||
380 | ** not the real size of the array, the key still can be in the array | ||
381 | ** part. In this case, do the "Xmilia trick" to check whether 'key-1' | ||
382 | ** is smaller than the real size. | ||
383 | ** The trick works as follow: let 'p' be an integer such that | ||
384 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
385 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
386 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
387 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
388 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
389 | ** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p', | ||
390 | ** therefore it will be larger or equal to 'alimit', and the check | ||
391 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than | ||
392 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
393 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
394 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
395 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
396 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
397 | ** if cannot be smaller than alimit. | ||
398 | */ | ||
399 | static int keyinarray (Table *t, lua_Integer key) { | ||
400 | lua_Unsigned alimit = t->alimit; | ||
401 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
402 | return 1; | ||
403 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
404 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
405 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
406 | return 1; | ||
407 | } | ||
408 | else | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | |||
413 | /* | ||
378 | ** {============================================================= | 414 | ** {============================================================= |
379 | ** Rehash | 415 | ** Rehash |
380 | ** ============================================================== | 416 | ** ============================================================== |
@@ -421,6 +457,12 @@ static int countint (lua_Integer key, unsigned int *nums) { | |||
421 | } | 457 | } |
422 | 458 | ||
423 | 459 | ||
460 | l_sinline int arraykeyisempty (const Table *t, lua_Integer key) { | ||
461 | int tag = *getArrTag(t, key); | ||
462 | return tagisempty(tag); | ||
463 | } | ||
464 | |||
465 | |||
424 | /* | 466 | /* |
425 | ** Count keys in array part of table 't': Fill 'nums[i]' with | 467 | ** Count keys in array part of table 't': Fill 'nums[i]' with |
426 | ** number of keys that will go into corresponding slice and return | 468 | ** number of keys that will go into corresponding slice and return |
@@ -443,7 +485,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) { | |||
443 | } | 485 | } |
444 | /* count elements in range (2^(lg - 1), 2^lg] */ | 486 | /* count elements in range (2^(lg - 1), 2^lg] */ |
445 | for (; i <= lim; i++) { | 487 | for (; i <= lim; i++) { |
446 | if (!isempty(&t->array[i-1])) | 488 | if (!arraykeyisempty(t, i)) |
447 | lc++; | 489 | lc++; |
448 | } | 490 | } |
449 | nums[lg] += lc; | 491 | nums[lg] += lc; |
@@ -555,7 +597,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
555 | unsigned int i; | 597 | unsigned int i; |
556 | Table newt; /* to keep the new hash part */ | 598 | Table newt; /* to keep the new hash part */ |
557 | unsigned int oldasize = setlimittosize(t); | 599 | unsigned int oldasize = setlimittosize(t); |
558 | TValue *newarray; | 600 | ArrayCell *newarray; |
559 | /* create new hash part with appropriate size into 'newt' */ | 601 | /* create new hash part with appropriate size into 'newt' */ |
560 | setnodevector(L, &newt, nhsize); | 602 | setnodevector(L, &newt, nhsize); |
561 | if (newasize < oldasize) { /* will array shrink? */ | 603 | if (newasize < oldasize) { /* will array shrink? */ |
@@ -563,14 +605,18 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
563 | exchangehashpart(t, &newt); /* and new hash */ | 605 | exchangehashpart(t, &newt); /* and new hash */ |
564 | /* re-insert into the new hash the elements from vanishing slice */ | 606 | /* re-insert into the new hash the elements from vanishing slice */ |
565 | for (i = newasize; i < oldasize; i++) { | 607 | for (i = newasize; i < oldasize; i++) { |
566 | if (!isempty(&t->array[i])) | 608 | int tag = *getArrTag(t, i + 1); |
567 | luaH_setint(L, t, i + 1, &t->array[i]); | 609 | if (!tagisempty(tag)) { /* a non-empty entry? */ |
610 | TValue aux; | ||
611 | farr2val(t, i + 1, tag, &aux); | ||
612 | luaH_setint(L, t, i + 1, &aux); | ||
613 | } | ||
568 | } | 614 | } |
569 | t->alimit = oldasize; /* restore current size... */ | 615 | t->alimit = oldasize; /* restore current size... */ |
570 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ | 616 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ |
571 | } | 617 | } |
572 | /* allocate new array */ | 618 | /* allocate new array */ |
573 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); | 619 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell); |
574 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ | 620 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ |
575 | freehash(L, &newt); /* release new hash part */ | 621 | freehash(L, &newt); /* release new hash part */ |
576 | luaM_error(L); /* raise error (with array unchanged) */ | 622 | luaM_error(L); /* raise error (with array unchanged) */ |
@@ -580,7 +626,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
580 | t->array = newarray; /* set new array part */ | 626 | t->array = newarray; /* set new array part */ |
581 | t->alimit = newasize; | 627 | t->alimit = newasize; |
582 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ | 628 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ |
583 | setempty(&t->array[i]); | 629 | *getArrTag(t, i + 1) = LUA_VEMPTY; |
584 | /* re-insert elements from old hash part into new parts */ | 630 | /* re-insert elements from old hash part into new parts */ |
585 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ | 631 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ |
586 | freehash(L, &newt); /* free old hash part */ | 632 | freehash(L, &newt); /* free old hash part */ |
@@ -719,41 +765,6 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { | |||
719 | } | 765 | } |
720 | 766 | ||
721 | 767 | ||
722 | /* | ||
723 | ** Check whether key is in the array part. If 'alimit' is not the real | ||
724 | ** size of the array, the key still can be in the array part. In this | ||
725 | ** case, do the "Xmilia trick" to check whether 'key-1' is smaller than | ||
726 | ** the real size. | ||
727 | ** The trick works as follow: let 'p' be an integer such that | ||
728 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
729 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
730 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
731 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
732 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
733 | ** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p', | ||
734 | ** therefore it will be larger or equal to 'alimit', and the check | ||
735 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than | ||
736 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
737 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
738 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
739 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
740 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
741 | ** if cannot be smaller than alimit. | ||
742 | */ | ||
743 | static int keyinarray (Table *t, lua_Integer key) { | ||
744 | lua_Unsigned alimit = t->alimit; | ||
745 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
746 | return 1; | ||
747 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
748 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
749 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
750 | return 1; | ||
751 | } | ||
752 | else | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | |||
757 | static const TValue *getintfromhash (Table *t, lua_Integer key) { | 768 | static const TValue *getintfromhash (Table *t, lua_Integer key) { |
758 | Node *n = hashint(t, key); | 769 | Node *n = hashint(t, key); |
759 | lua_assert(l_castS2U(key) - 1u >= luaH_realasize(t)); | 770 | lua_assert(l_castS2U(key) - 1u >= luaH_realasize(t)); |
@@ -770,15 +781,8 @@ static const TValue *getintfromhash (Table *t, lua_Integer key) { | |||
770 | } | 781 | } |
771 | 782 | ||
772 | 783 | ||
773 | l_sinline int arraykeyisempty (Table *t, lua_Integer key) { | ||
774 | int tag = *getArrTag(t, key); | ||
775 | return tagisempty(tag); | ||
776 | } | ||
777 | |||
778 | |||
779 | static int hashkeyisempty (Table *t, lua_Integer key) { | 784 | static int hashkeyisempty (Table *t, lua_Integer key) { |
780 | const TValue *val = getintfromhash(t, key); | 785 | const TValue *val = getintfromhash(t, key); |
781 | lua_assert(!keyinarray(t, key)); | ||
782 | return isempty(val); | 786 | return isempty(val); |
783 | } | 787 | } |
784 | 788 | ||
@@ -797,7 +801,7 @@ int luaH_getint (Table *t, lua_Integer key, TValue *res) { | |||
797 | if (keyinarray(t, key)) { | 801 | if (keyinarray(t, key)) { |
798 | int tag = *getArrTag(t, key); | 802 | int tag = *getArrTag(t, key); |
799 | if (!tagisempty(tag)) { | 803 | if (!tagisempty(tag)) { |
800 | arr2val(t, key, tag, res); | 804 | farr2val(t, key, tag, res); |
801 | return HOK; /* success */ | 805 | return HOK; /* success */ |
802 | } | 806 | } |
803 | else | 807 | else |
@@ -900,7 +904,7 @@ int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | |||
900 | if (keyinarray(t, key)) { | 904 | if (keyinarray(t, key)) { |
901 | lu_byte *tag = getArrTag(t, key); | 905 | lu_byte *tag = getArrTag(t, key); |
902 | if (!tagisempty(*tag)) { | 906 | if (!tagisempty(*tag)) { |
903 | val2arr(t, key, tag, val); | 907 | fval2arr(t, key, tag, val); |
904 | return HOK; /* success */ | 908 | return HOK; /* success */ |
905 | } | 909 | } |
906 | else | 910 | else |
@@ -956,7 +960,7 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key, | |||
956 | } | 960 | } |
957 | else { /* array entry */ | 961 | else { /* array entry */ |
958 | hres = ~hres; /* real index */ | 962 | hres = ~hres; /* real index */ |
959 | val2arr(t, hres, getArrTag(t, hres), value); | 963 | fval2arr(t, hres, getArrTag(t, hres), value); |
960 | } | 964 | } |
961 | } | 965 | } |
962 | 966 | ||
@@ -1087,11 +1091,11 @@ lua_Unsigned luaH_getn (Table *t) { | |||
1087 | /* 'limit' is zero or present in table */ | 1091 | /* 'limit' is zero or present in table */ |
1088 | if (!limitequalsasize(t)) { /* (2)? */ | 1092 | if (!limitequalsasize(t)) { /* (2)? */ |
1089 | /* 'limit' > 0 and array has more elements after 'limit' */ | 1093 | /* 'limit' > 0 and array has more elements after 'limit' */ |
1090 | if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ | 1094 | if (arraykeyisempty(t, limit + 1)) /* 'limit + 1' is empty? */ |
1091 | return limit; /* this is the boundary */ | 1095 | return limit; /* this is the boundary */ |
1092 | /* else, try last element in the array */ | 1096 | /* else, try last element in the array */ |
1093 | limit = luaH_realasize(t); | 1097 | limit = luaH_realasize(t); |
1094 | if (isempty(&t->array[limit - 1])) { /* empty? */ | 1098 | if (arraykeyisempty(t, limit)) { /* empty? */ |
1095 | /* there must be a boundary in the array after old limit, | 1099 | /* there must be a boundary in the array after old limit, |
1096 | and it must be a valid new limit */ | 1100 | and it must be a valid new limit */ |
1097 | unsigned int boundary = binsearch(t, t->alimit, limit); | 1101 | unsigned int boundary = binsearch(t, t->alimit, limit); |
@@ -1102,7 +1106,7 @@ lua_Unsigned luaH_getn (Table *t) { | |||
1102 | } | 1106 | } |
1103 | /* (3) 'limit' is the last element and either is zero or present in table */ | 1107 | /* (3) 'limit' is the last element and either is zero or present in table */ |
1104 | lua_assert(limit == luaH_realasize(t) && | 1108 | lua_assert(limit == luaH_realasize(t) && |
1105 | (limit == 0 || !isempty(&t->array[limit - 1]))); | 1109 | (limit == 0 || !arraykeyisempty(t, limit))); |
1106 | if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1))) | 1110 | if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1))) |
1107 | return limit; /* 'limit + 1' is absent */ | 1111 | return limit; /* 'limit + 1' is absent */ |
1108 | else /* 'limit + 1' is also present */ | 1112 | else /* 'limit + 1' is also present */ |