aboutsummaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltable.c')
-rw-r--r--ltable.c128
1 files changed, 79 insertions, 49 deletions
diff --git a/ltable.c b/ltable.c
index 3f95ab0c..d436cf6e 100644
--- a/ltable.c
+++ b/ltable.c
@@ -719,16 +719,38 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
719} 719}
720 720
721 721
722static const TValue *getintfromarray (Table *t, lua_Integer key) { 722/*
723 if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ 723** Check whether key is in the array part. If 'alimit' is not the real
724 return &t->array[key - 1]; 724** size of the array, the key still can be in the array part. In this
725 else if (!limitequalsasize(t) && /* key still may be in the array part? */ 725** case, do the "Xmilia trick" to check whether 'key-1' is smaller than
726 (l_castS2U(key) == t->alimit + 1 || 726** the real size.
727 l_castS2U(key) - 1u < luaH_realasize(t))) { 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*/
743static 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)) {
728 t->alimit = cast_uint(key); /* probably '#t' is here now */ 749 t->alimit = cast_uint(key); /* probably '#t' is here now */
729 return &t->array[key - 1]; 750 return 1;
730 } 751 }
731 else return NULL; /* key is not in the array part */ 752 else
753 return 0;
732} 754}
733 755
734 756
@@ -748,20 +770,16 @@ static const TValue *getintfromhash (Table *t, lua_Integer key) {
748} 770}
749 771
750 772
751/* 773l_sinline int arraykeyisempty (Table *t, lua_Integer key) {
752** Search function for integers. If integer is inside 'alimit', get it 774 int tag = *getArrTag(t, key);
753** directly from the array part. Otherwise, if 'alimit' is not equal to 775 return tagisempty(tag);
754** the real size of the array, key still can be in the array part. In 776}
755** this case, try to avoid a call to 'luaH_realasize' when key is just 777
756** one more than the limit (so that it can be incremented without 778
757** changing the real size of the array). 779static int hashkeyisempty (Table *t, lua_Integer key) {
758*/ 780 const TValue *val = getintfromhash(t, key);
759static const TValue *Hgetint (Table *t, lua_Integer key) { 781 lua_assert(!keyinarray(t, key));
760 const TValue *slot = getintfromarray(t, key); 782 return isempty(val);
761 if (slot != NULL)
762 return slot;
763 else
764 return getintfromhash(t, key);
765} 783}
766 784
767 785
@@ -776,7 +794,17 @@ static int finishnodeget (const TValue *val, TValue *res) {
776 794
777 795
778int luaH_getint (Table *t, lua_Integer key, TValue *res) { 796int luaH_getint (Table *t, lua_Integer key, TValue *res) {
779 return finishnodeget(Hgetint(t, key), res); 797 if (keyinarray(t, key)) {
798 int tag = *getArrTag(t, key);
799 if (!tagisempty(tag)) {
800 arr2val(t, key, tag, res);
801 return HOK; /* success */
802 }
803 else
804 return ~cast_int(key); /* empty slot in the array part */
805 }
806 else
807 return finishnodeget(getintfromhash(t, key), res);
780} 808}
781 809
782 810
@@ -832,25 +860,28 @@ TString *luaH_getstrkey (Table *t, TString *key) {
832/* 860/*
833** main search function 861** main search function
834*/ 862*/
835static const TValue *Hget (Table *t, const TValue *key) { 863int luaH_get (Table *t, const TValue *key, TValue *res) {
864 const TValue *slot;
836 switch (ttypetag(key)) { 865 switch (ttypetag(key)) {
837 case LUA_VSHRSTR: return luaH_Hgetshortstr(t, tsvalue(key)); 866 case LUA_VSHRSTR:
838 case LUA_VNUMINT: return Hgetint(t, ivalue(key)); 867 slot = luaH_Hgetshortstr(t, tsvalue(key));
839 case LUA_VNIL: return &absentkey; 868 break;
869 case LUA_VNUMINT:
870 return luaH_getint(t, ivalue(key), res);
871 case LUA_VNIL:
872 slot = &absentkey;
873 break;
840 case LUA_VNUMFLT: { 874 case LUA_VNUMFLT: {
841 lua_Integer k; 875 lua_Integer k;
842 if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */ 876 if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */
843 return Hgetint(t, k); /* use specialized version */ 877 return luaH_getint(t, k, res); /* use specialized version */
844 /* else... */ 878 /* else... */
845 } /* FALLTHROUGH */ 879 } /* FALLTHROUGH */
846 default: 880 default:
847 return getgeneric(t, key, 0); 881 slot = getgeneric(t, key, 0);
882 break;
848 } 883 }
849} 884 return finishnodeget(slot, res);
850
851
852int luaH_get (Table *t, const TValue *key, TValue *res) {
853 return finishnodeget(Hget(t, key), res);
854} 885}
855 886
856 887
@@ -866,10 +897,10 @@ static int finishnodeset (Table *t, const TValue *slot, TValue *val) {
866 897
867 898
868int luaH_psetint (Table *t, lua_Integer key, TValue *val) { 899int luaH_psetint (Table *t, lua_Integer key, TValue *val) {
869 const TValue *slot = getintfromarray(t, key); 900 if (keyinarray(t, key)) {
870 if (slot != NULL) { 901 lu_byte *tag = getArrTag(t, key);
871 if (!ttisnil(slot)) { 902 if (!tagisempty(*tag)) {
872 setobj(((lua_State*)NULL), cast(TValue*, slot), val); 903 val2arr(t, key, tag, val);
873 return HOK; /* success */ 904 return HOK; /* success */
874 } 905 }
875 else 906 else
@@ -973,27 +1004,26 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
973 j *= 2; 1004 j *= 2;
974 else { 1005 else {
975 j = LUA_MAXINTEGER; 1006 j = LUA_MAXINTEGER;
976 if (isempty(Hgetint(t, j))) /* t[j] not present? */ 1007 if (hashkeyisempty(t, j)) /* t[j] not present? */
977 break; /* 'j' now is an absent index */ 1008 break; /* 'j' now is an absent index */
978 else /* weird case */ 1009 else /* weird case */
979 return j; /* well, max integer is a boundary... */ 1010 return j; /* well, max integer is a boundary... */
980 } 1011 }
981 } while (!isempty(Hgetint(t, j))); /* repeat until an absent t[j] */ 1012 } while (!hashkeyisempty(t, j)); /* repeat until an absent t[j] */
982 /* i < j && t[i] present && t[j] absent */ 1013 /* i < j && t[i] present && t[j] absent */
983 while (j - i > 1u) { /* do a binary search between them */ 1014 while (j - i > 1u) { /* do a binary search between them */
984 lua_Unsigned m = (i + j) / 2; 1015 lua_Unsigned m = (i + j) / 2;
985 if (isempty(Hgetint(t, m))) j = m; 1016 if (hashkeyisempty(t, m)) j = m;
986 else i = m; 1017 else i = m;
987 } 1018 }
988 return i; 1019 return i;
989} 1020}
990 1021
991 1022
992static unsigned int binsearch (const TValue *array, unsigned int i, 1023static unsigned int binsearch (Table *array, unsigned int i, unsigned int j) {
993 unsigned int j) {
994 while (j - i > 1u) { /* binary search */ 1024 while (j - i > 1u) { /* binary search */
995 unsigned int m = (i + j) / 2; 1025 unsigned int m = (i + j) / 2;
996 if (isempty(&array[m - 1])) j = m; 1026 if (arraykeyisempty(array, m)) j = m;
997 else i = m; 1027 else i = m;
998 } 1028 }
999 return i; 1029 return i;
@@ -1034,9 +1064,9 @@ static unsigned int binsearch (const TValue *array, unsigned int i,
1034*/ 1064*/
1035lua_Unsigned luaH_getn (Table *t) { 1065lua_Unsigned luaH_getn (Table *t) {
1036 unsigned int limit = t->alimit; 1066 unsigned int limit = t->alimit;
1037 if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */ 1067 if (limit > 0 && arraykeyisempty(t, limit)) { /* (1)? */
1038 /* there must be a boundary before 'limit' */ 1068 /* there must be a boundary before 'limit' */
1039 if (limit >= 2 && !isempty(&t->array[limit - 2])) { 1069 if (limit >= 2 && !arraykeyisempty(t, limit - 1)) {
1040 /* 'limit - 1' is a boundary; can it be a new limit? */ 1070 /* 'limit - 1' is a boundary; can it be a new limit? */
1041 if (ispow2realasize(t) && !ispow2(limit - 1)) { 1071 if (ispow2realasize(t) && !ispow2(limit - 1)) {
1042 t->alimit = limit - 1; 1072 t->alimit = limit - 1;
@@ -1045,7 +1075,7 @@ lua_Unsigned luaH_getn (Table *t) {
1045 return limit - 1; 1075 return limit - 1;
1046 } 1076 }
1047 else { /* must search for a boundary in [0, limit] */ 1077 else { /* must search for a boundary in [0, limit] */
1048 unsigned int boundary = binsearch(t->array, 0, limit); 1078 unsigned int boundary = binsearch(t, 0, limit);
1049 /* can this boundary represent the real size of the array? */ 1079 /* can this boundary represent the real size of the array? */
1050 if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) { 1080 if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) {
1051 t->alimit = boundary; /* use it as the new limit */ 1081 t->alimit = boundary; /* use it as the new limit */
@@ -1064,7 +1094,7 @@ lua_Unsigned luaH_getn (Table *t) {
1064 if (isempty(&t->array[limit - 1])) { /* empty? */ 1094 if (isempty(&t->array[limit - 1])) { /* empty? */
1065 /* there must be a boundary in the array after old limit, 1095 /* there must be a boundary in the array after old limit,
1066 and it must be a valid new limit */ 1096 and it must be a valid new limit */
1067 unsigned int boundary = binsearch(t->array, t->alimit, limit); 1097 unsigned int boundary = binsearch(t, t->alimit, limit);
1068 t->alimit = boundary; 1098 t->alimit = boundary;
1069 return boundary; 1099 return boundary;
1070 } 1100 }
@@ -1073,7 +1103,7 @@ lua_Unsigned luaH_getn (Table *t) {
1073 /* (3) 'limit' is the last element and either is zero or present in table */ 1103 /* (3) 'limit' is the last element and either is zero or present in table */
1074 lua_assert(limit == luaH_realasize(t) && 1104 lua_assert(limit == luaH_realasize(t) &&
1075 (limit == 0 || !isempty(&t->array[limit - 1]))); 1105 (limit == 0 || !isempty(&t->array[limit - 1])));
1076 if (isdummy(t) || isempty(Hgetint(t, cast(lua_Integer, limit + 1)))) 1106 if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1)))
1077 return limit; /* 'limit + 1' is absent */ 1107 return limit; /* 'limit + 1' is absent */
1078 else /* 'limit + 1' is also present */ 1108 else /* 'limit + 1' is also present */
1079 return hash_search(t, limit); 1109 return hash_search(t, limit);