diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-12-05 14:27:58 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-12-05 14:27:58 -0300 |
commit | bb93f04d87cfc093757dc712905e1fe3fbe65f58 (patch) | |
tree | 14f154ea303b10d543266b1e36ad8fb441695a66 /ltable.c | |
parent | 975d4e0592f980aef09c432302496d834249b6a7 (diff) | |
download | lua-bb93f04d87cfc093757dc712905e1fe3fbe65f58.tar.gz lua-bb93f04d87cfc093757dc712905e1fe3fbe65f58.tar.bz2 lua-bb93f04d87cfc093757dc712905e1fe3fbe65f58.zip |
Refactoring of 'luaH_newkey'
Function broke in two and some checks moved to the caller. (We may
want to call it without the checks.)
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 130 |
1 files changed, 77 insertions, 53 deletions
@@ -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) { |