diff options
| -rw-r--r-- | lobject.h | 5 | ||||
| -rw-r--r-- | ltable.c | 130 |
2 files changed, 79 insertions, 56 deletions
| @@ -750,10 +750,9 @@ typedef union Node { | |||
| 750 | 750 | ||
| 751 | 751 | ||
| 752 | /* copy a value into a key */ | 752 | /* copy a value into a key */ |
| 753 | #define setnodekey(L,node,obj) \ | 753 | #define setnodekey(node,obj) \ |
| 754 | { Node *n_=(node); const TValue *io_=(obj); \ | 754 | { Node *n_=(node); const TValue *io_=(obj); \ |
| 755 | n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \ | 755 | n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; } |
| 756 | checkliveness(L,io_); } | ||
| 757 | 756 | ||
| 758 | 757 | ||
| 759 | /* copy a value from a key */ | 758 | /* copy a value from a key */ |
| @@ -294,14 +294,34 @@ static const TValue *getgeneric (Table *t, const TValue *key, int deadok) { | |||
| 294 | 294 | ||
| 295 | 295 | ||
| 296 | /* | 296 | /* |
| 297 | ** returns the index for 'k' if 'k' is an appropriate key to live in | 297 | ** Return the index 'k' (converted to an unsigned) if it is inside |
| 298 | ** the array part of a table, 0 otherwise. | 298 | ** the range [1, limit]. |
| 299 | */ | 299 | */ |
| 300 | static unsigned int arrayindex (lua_Integer k) { | 300 | static unsigned checkrange (lua_Integer k, unsigned limit) { |
| 301 | if (l_castS2U(k) - 1u < MAXASIZE) /* 'k' in [1, MAXASIZE]? */ | 301 | return (l_castS2U(k) - 1u < limit) ? cast_uint(k) : 0; |
| 302 | return cast_uint(k); /* 'key' is an appropriate array index */ | 302 | } |
| 303 | else | 303 | |
| 304 | return 0; | 304 | |
| 305 | /* | ||
| 306 | ** Return the index 'k' if 'k' is an appropriate key to live in the | ||
| 307 | ** array part of a table, 0 otherwise. | ||
| 308 | */ | ||
| 309 | #define arrayindex(k) checkrange(k, MAXASIZE) | ||
| 310 | |||
| 311 | |||
| 312 | /* | ||
| 313 | ** Check whether an integer key is in the array part of a table and | ||
| 314 | ** return its index there, or zero. | ||
| 315 | */ | ||
| 316 | #define ikeyinarray(t,k) checkrange(k, t->asize) | ||
| 317 | |||
| 318 | |||
| 319 | /* | ||
| 320 | ** Check whether a key is in the array part of a table and return its | ||
| 321 | ** index there, or zero. | ||
| 322 | */ | ||
| 323 | static unsigned keyinarray (Table *t, const TValue *key) { | ||
| 324 | return (ttisinteger(key)) ? ikeyinarray(t, ivalue(key)) : 0; | ||
| 305 | } | 325 | } |
| 306 | 326 | ||
| 307 | 327 | ||
| @@ -314,8 +334,8 @@ static unsigned findindex (lua_State *L, Table *t, TValue *key, | |||
| 314 | unsigned asize) { | 334 | unsigned asize) { |
| 315 | unsigned int i; | 335 | unsigned int i; |
| 316 | if (ttisnil(key)) return 0; /* first iteration */ | 336 | if (ttisnil(key)) return 0; /* first iteration */ |
| 317 | i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; | 337 | i = keyinarray(t, key); |
| 318 | if (i - 1u < asize) /* is 'key' inside array part? */ | 338 | if (i != 0) /* is 'key' inside array part? */ |
| 319 | return i; /* yes; that's the index */ | 339 | return i; /* yes; that's the index */ |
| 320 | else { | 340 | else { |
| 321 | const TValue *n = getgeneric(t, key, 1); | 341 | const TValue *n = getgeneric(t, key, 1); |
| @@ -370,14 +390,6 @@ static void freehash (lua_State *L, Table *t) { | |||
| 370 | 390 | ||
| 371 | 391 | ||
| 372 | /* | 392 | /* |
| 373 | ** Check whether an integer key is in the array part of a table. | ||
| 374 | */ | ||
| 375 | l_sinline int keyinarray (Table *t, lua_Integer key) { | ||
| 376 | return (l_castS2U(key) - 1u < t->asize); /* 'key' in [1, t->asize]? */ | ||
| 377 | } | ||
| 378 | |||
| 379 | |||
| 380 | /* | ||
| 381 | ** {============================================================= | 393 | ** {============================================================= |
| 382 | ** Rehash | 394 | ** Rehash |
| 383 | ** ============================================================== | 395 | ** ============================================================== |
| @@ -829,36 +841,18 @@ static Node *getfreepos (Table *t) { | |||
| 829 | ** position is free. If not, check whether colliding node is in its main | 841 | ** position is free. If not, check whether colliding node is in its main |
| 830 | ** position or not: if it is not, move colliding node to an empty place | 842 | ** position or not: if it is not, move colliding node to an empty place |
| 831 | ** and put new key in its main position; otherwise (colliding node is in | 843 | ** and put new key in its main position; otherwise (colliding node is in |
| 832 | ** its main position), new key goes to an empty position. | 844 | ** its main position), new key goes to an empty position. Return 0 if |
| 845 | ** could not insert key (could not find a free space). | ||
| 833 | */ | 846 | */ |
| 834 | static void luaH_newkey (lua_State *L, Table *t, const TValue *key, | 847 | static int insertkey (Table *t, const TValue *key, TValue *value) { |
| 835 | TValue *value) { | 848 | Node *mp = mainpositionTV(t, key); |
| 836 | Node *mp; | 849 | /* table cannot already contain the key */ |
| 837 | TValue aux; | 850 | lua_assert(isabstkey(getgeneric(t, key, 0))); |
| 838 | if (l_unlikely(ttisnil(key))) | ||
| 839 | luaG_runerror(L, "table index is nil"); | ||
| 840 | else if (ttisfloat(key)) { | ||
| 841 | lua_Number f = fltvalue(key); | ||
| 842 | lua_Integer k; | ||
| 843 | if (luaV_flttointeger(f, &k, F2Ieq)) { /* does key fit in an integer? */ | ||
| 844 | setivalue(&aux, k); | ||
| 845 | key = &aux; /* insert it as an integer */ | ||
| 846 | } | ||
| 847 | else if (l_unlikely(luai_numisnan(f))) | ||
| 848 | luaG_runerror(L, "table index is NaN"); | ||
| 849 | } | ||
| 850 | if (ttisnil(value)) | ||
| 851 | return; /* do not insert nil values */ | ||
| 852 | mp = mainpositionTV(t, key); | ||
| 853 | if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ | 851 | if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ |
| 854 | Node *othern; | 852 | Node *othern; |
| 855 | Node *f = getfreepos(t); /* get a free place */ | 853 | Node *f = getfreepos(t); /* get a free place */ |
| 856 | if (f == NULL) { /* cannot find a free place? */ | 854 | if (f == NULL) /* cannot find a free place? */ |
| 857 | rehash(L, t, key); /* grow table */ | 855 | return 0; |
| 858 | /* whatever called 'newkey' takes care of TM cache */ | ||
| 859 | luaH_set(L, t, key, value); /* insert key into grown table */ | ||
| 860 | return; | ||
| 861 | } | ||
| 862 | lua_assert(!isdummy(t)); | 856 | lua_assert(!isdummy(t)); |
| 863 | othern = mainpositionfromnode(t, mp); | 857 | othern = mainpositionfromnode(t, mp); |
| 864 | if (othern != mp) { /* is colliding node out of its main position? */ | 858 | if (othern != mp) { /* is colliding node out of its main position? */ |
| @@ -882,16 +876,31 @@ static void luaH_newkey (lua_State *L, Table *t, const TValue *key, | |||
| 882 | mp = f; | 876 | mp = f; |
| 883 | } | 877 | } |
| 884 | } | 878 | } |
| 885 | setnodekey(L, mp, key); | 879 | setnodekey(mp, key); |
| 886 | luaC_barrierback(L, obj2gco(t), key); | ||
| 887 | lua_assert(isempty(gval(mp))); | 880 | lua_assert(isempty(gval(mp))); |
| 888 | setobj2t(L, gval(mp), value); | 881 | setobj2t(cast(lua_State *, 0), gval(mp), value); |
| 882 | return 1; | ||
| 883 | } | ||
| 884 | |||
| 885 | |||
| 886 | static void luaH_newkey (lua_State *L, Table *t, const TValue *key, | ||
| 887 | TValue *value) { | ||
| 888 | if (!ttisnil(value)) { /* do not insert nil values */ | ||
| 889 | int done = insertkey(t, key, value); | ||
| 890 | if (done) | ||
| 891 | luaC_barrierback(L, obj2gco(t), key); | ||
| 892 | else { /* could not find a free place? */ | ||
| 893 | rehash(L, t, key); /* grow table */ | ||
| 894 | /* whatever called 'newkey' takes care of TM cache */ | ||
| 895 | luaH_set(L, t, key, value); /* insert key into grown table */ | ||
| 896 | } | ||
| 897 | } | ||
| 889 | } | 898 | } |
| 890 | 899 | ||
| 891 | 900 | ||
| 892 | static const TValue *getintfromhash (Table *t, lua_Integer key) { | 901 | static const TValue *getintfromhash (Table *t, lua_Integer key) { |
| 893 | Node *n = hashint(t, key); | 902 | Node *n = hashint(t, key); |
| 894 | lua_assert(!keyinarray(t, key)); | 903 | lua_assert(!ikeyinarray(t, key)); |
| 895 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 904 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
| 896 | if (keyisinteger(n) && keyival(n) == key) | 905 | if (keyisinteger(n) && keyival(n) == key) |
| 897 | return gval(n); /* that's it */ | 906 | return gval(n); /* that's it */ |
| @@ -920,10 +929,11 @@ static lu_byte finishnodeget (const TValue *val, TValue *res) { | |||
| 920 | 929 | ||
| 921 | 930 | ||
| 922 | lu_byte luaH_getint (Table *t, lua_Integer key, TValue *res) { | 931 | lu_byte luaH_getint (Table *t, lua_Integer key, TValue *res) { |
| 923 | if (keyinarray(t, key)) { | 932 | unsigned k = ikeyinarray(t, key); |
| 924 | lu_byte tag = *getArrTag(t, key - 1); | 933 | if (k > 0) { |
| 934 | lu_byte tag = *getArrTag(t, k - 1); | ||
| 925 | if (!tagisempty(tag)) | 935 | if (!tagisempty(tag)) |
| 926 | farr2val(t, cast_uint(key) - 1, tag, res); | 936 | farr2val(t, k - 1, tag, res); |
| 927 | return tag; | 937 | return tag; |
| 928 | } | 938 | } |
| 929 | else | 939 | else |
| @@ -1031,7 +1041,7 @@ static int rawfinishnodeset (const TValue *slot, TValue *val) { | |||
| 1031 | 1041 | ||
| 1032 | 1042 | ||
| 1033 | int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | 1043 | int luaH_psetint (Table *t, lua_Integer key, TValue *val) { |
| 1034 | lua_assert(!keyinarray(t, key)); | 1044 | lua_assert(!ikeyinarray(t, key)); |
| 1035 | return finishnodeset(t, getintfromhash(t, key), val); | 1045 | return finishnodeset(t, getintfromhash(t, key), val); |
| 1036 | } | 1046 | } |
| 1037 | 1047 | ||
| @@ -1081,6 +1091,19 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key, | |||
| 1081 | TValue *value, int hres) { | 1091 | TValue *value, int hres) { |
| 1082 | lua_assert(hres != HOK); | 1092 | lua_assert(hres != HOK); |
| 1083 | if (hres == HNOTFOUND) { | 1093 | if (hres == HNOTFOUND) { |
| 1094 | TValue aux; | ||
| 1095 | if (l_unlikely(ttisnil(key))) | ||
| 1096 | luaG_runerror(L, "table index is nil"); | ||
| 1097 | else if (ttisfloat(key)) { | ||
| 1098 | lua_Number f = fltvalue(key); | ||
| 1099 | lua_Integer k; | ||
| 1100 | if (luaV_flttointeger(f, &k, F2Ieq)) { | ||
| 1101 | setivalue(&aux, k); /* key is equal to an integer */ | ||
| 1102 | key = &aux; /* insert it as an integer */ | ||
| 1103 | } | ||
| 1104 | else if (l_unlikely(luai_numisnan(f))) | ||
| 1105 | luaG_runerror(L, "table index is NaN"); | ||
| 1106 | } | ||
| 1084 | luaH_newkey(L, t, key, value); | 1107 | luaH_newkey(L, t, key, value); |
| 1085 | } | 1108 | } |
| 1086 | else if (hres > 0) { /* regular Node? */ | 1109 | else if (hres > 0) { /* regular Node? */ |
| @@ -1109,8 +1132,9 @@ void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { | |||
| 1109 | ** integers cannot be keys to metamethods.) | 1132 | ** integers cannot be keys to metamethods.) |
| 1110 | */ | 1133 | */ |
| 1111 | void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { | 1134 | void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { |
| 1112 | if (keyinarray(t, key)) | 1135 | unsigned ik = ikeyinarray(t, key); |
| 1113 | obj2arr(t, cast_uint(key) - 1, value); | 1136 | if (ik > 0) |
| 1137 | obj2arr(t, ik - 1, value); | ||
| 1114 | else { | 1138 | else { |
| 1115 | int ok = rawfinishnodeset(getintfromhash(t, key), value); | 1139 | int ok = rawfinishnodeset(getintfromhash(t, key), value); |
| 1116 | if (!ok) { | 1140 | if (!ok) { |
