diff options
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 128 |
1 files changed, 79 insertions, 49 deletions
@@ -719,16 +719,38 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { | |||
719 | } | 719 | } |
720 | 720 | ||
721 | 721 | ||
722 | static 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 | */ | ||
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)) { | ||
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 | /* | 773 | l_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). | 779 | static int hashkeyisempty (Table *t, lua_Integer key) { |
758 | */ | 780 | const TValue *val = getintfromhash(t, key); |
759 | static 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 | ||
778 | int luaH_getint (Table *t, lua_Integer key, TValue *res) { | 796 | int 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 | */ |
835 | static const TValue *Hget (Table *t, const TValue *key) { | 863 | int 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 | |||
852 | int 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 | ||
868 | int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | 899 | int 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 | ||
992 | static unsigned int binsearch (const TValue *array, unsigned int i, | 1023 | static 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 | */ |
1035 | lua_Unsigned luaH_getn (Table *t) { | 1065 | lua_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); |