diff options
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 128 |
1 files changed, 71 insertions, 57 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 1.61 2000/12/22 16:57:46 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 1.62 2000/12/28 12:55:41 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -23,7 +23,6 @@ | |||
23 | #include "lmem.h" | 23 | #include "lmem.h" |
24 | #include "lobject.h" | 24 | #include "lobject.h" |
25 | #include "lstate.h" | 25 | #include "lstate.h" |
26 | #include "lstring.h" | ||
27 | #include "ltable.h" | 26 | #include "ltable.h" |
28 | 27 | ||
29 | 28 | ||
@@ -31,6 +30,9 @@ | |||
31 | #define TagDefault LUA_TTABLE | 30 | #define TagDefault LUA_TTABLE |
32 | 31 | ||
33 | 32 | ||
33 | #define hashnum(t,n) (&t->node[(luint32)(lint32)(n)&(t->size-1)]) | ||
34 | #define hashstr(t,str) (&t->node[(str)->u.s.hash&(t->size-1)]) | ||
35 | |||
34 | 36 | ||
35 | /* | 37 | /* |
36 | ** returns the `main' position of an element in a table (that is, the index | 38 | ** returns the `main' position of an element in a table (that is, the index |
@@ -40,11 +42,9 @@ Node *luaH_mainposition (const Hash *t, const TObject *key) { | |||
40 | luint32 h; | 42 | luint32 h; |
41 | switch (ttype(key)) { | 43 | switch (ttype(key)) { |
42 | case LUA_TNUMBER: | 44 | case LUA_TNUMBER: |
43 | h = (luint32)(lint32)nvalue(key); | 45 | return hashnum(t, nvalue(key)); |
44 | break; | ||
45 | case LUA_TSTRING: | 46 | case LUA_TSTRING: |
46 | h = tsvalue(key)->u.s.hash; | 47 | return hashstr(t, tsvalue(key)); |
47 | break; | ||
48 | case LUA_TUSERDATA: | 48 | case LUA_TUSERDATA: |
49 | h = IntPoint(tsvalue(key)); | 49 | h = IntPoint(tsvalue(key)); |
50 | break; | 50 | break; |
@@ -57,31 +57,26 @@ Node *luaH_mainposition (const Hash *t, const TObject *key) { | |||
57 | default: | 57 | default: |
58 | return NULL; /* invalid key */ | 58 | return NULL; /* invalid key */ |
59 | } | 59 | } |
60 | LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)), | ||
61 | "a&(x-1) == a%x, for x power of 2"); | ||
62 | return &t->node[h&(t->size-1)]; | 60 | return &t->node[h&(t->size-1)]; |
63 | } | 61 | } |
64 | 62 | ||
65 | 63 | ||
66 | static const TObject *luaH_getany (lua_State *L, const Hash *t, | 64 | static const TObject *luaH_getany (const Hash *t, const TObject *key) { |
67 | const TObject *key) { | ||
68 | Node *n = luaH_mainposition(t, key); | 65 | Node *n = luaH_mainposition(t, key); |
69 | if (!n) | 66 | while (n) { |
70 | lua_error(L, "table index is nil"); | ||
71 | else do { | ||
72 | if (luaO_equalObj(key, &n->key)) | 67 | if (luaO_equalObj(key, &n->key)) |
73 | return &n->val; | 68 | return &n->val; |
74 | n = n->next; | 69 | n = n->next; |
75 | } while (n); | 70 | } |
76 | return &luaO_nilobject; /* key not found */ | 71 | return &luaO_nilobject; /* key not found */ |
77 | } | 72 | } |
78 | 73 | ||
79 | 74 | ||
80 | /* specialized version for numbers */ | 75 | /* specialized version for numbers */ |
81 | const TObject *luaH_getnum (const Hash *t, lua_Number key) { | 76 | const TObject *luaH_getnum (const Hash *t, lua_Number key) { |
82 | Node *n = &t->node[(luint32)(lint32)key&(t->size-1)]; | 77 | Node *n = hashnum(t, key); |
83 | do { | 78 | do { |
84 | if (ttype(&n->key) == LUA_TNUMBER && nvalue(&n->key) == key) | 79 | if (nvalue(&n->key) == key && ttype(&n->key) == LUA_TNUMBER) |
85 | return &n->val; | 80 | return &n->val; |
86 | n = n->next; | 81 | n = n->next; |
87 | } while (n); | 82 | } while (n); |
@@ -91,9 +86,9 @@ const TObject *luaH_getnum (const Hash *t, lua_Number key) { | |||
91 | 86 | ||
92 | /* specialized version for strings */ | 87 | /* specialized version for strings */ |
93 | const TObject *luaH_getstr (const Hash *t, TString *key) { | 88 | const TObject *luaH_getstr (const Hash *t, TString *key) { |
94 | Node *n = &t->node[key->u.s.hash&(t->size-1)]; | 89 | Node *n = hashstr(t, key); |
95 | do { | 90 | do { |
96 | if (ttype(&n->key) == LUA_TSTRING && tsvalue(&n->key) == key) | 91 | if (tsvalue(&n->key) == key && ttype(&n->key) == LUA_TSTRING) |
97 | return &n->val; | 92 | return &n->val; |
98 | n = n->next; | 93 | n = n->next; |
99 | } while (n); | 94 | } while (n); |
@@ -101,11 +96,11 @@ const TObject *luaH_getstr (const Hash *t, TString *key) { | |||
101 | } | 96 | } |
102 | 97 | ||
103 | 98 | ||
104 | const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) { | 99 | const TObject *luaH_get (const Hash *t, const TObject *key) { |
105 | switch (ttype(key)) { | 100 | switch (ttype(key)) { |
106 | case LUA_TNUMBER: return luaH_getnum(t, nvalue(key)); | 101 | case LUA_TNUMBER: return luaH_getnum(t, nvalue(key)); |
107 | case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); | 102 | case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); |
108 | default: return luaH_getany(L, t, key); | 103 | default: return luaH_getany(t, key); |
109 | } | 104 | } |
110 | } | 105 | } |
111 | 106 | ||
@@ -115,7 +110,7 @@ Node *luaH_next (lua_State *L, const Hash *t, const TObject *key) { | |||
115 | if (ttype(key) == LUA_TNIL) | 110 | if (ttype(key) == LUA_TNIL) |
116 | i = 0; /* first iteration */ | 111 | i = 0; /* first iteration */ |
117 | else { | 112 | else { |
118 | const TObject *v = luaH_get(L, t, key); | 113 | const TObject *v = luaH_get(t, key); |
119 | if (v == &luaO_nilobject) | 114 | if (v == &luaO_nilobject) |
120 | lua_error(L, "invalid key for `next'"); | 115 | lua_error(L, "invalid key for `next'"); |
121 | i = (int)(((const char *)v - | 116 | i = (int)(((const char *)v - |
@@ -224,30 +219,17 @@ static void rehash (lua_State *L, Hash *t) { | |||
224 | 219 | ||
225 | 220 | ||
226 | /* | 221 | /* |
227 | ** inserts a key into a hash table; first, check whether key is | 222 | ** inserts a new key into a hash table; first, check whether key's main |
228 | ** already present; if not, check whether key's main position is free; | 223 | ** position is free; if not, check whether colliding node is in its main |
229 | ** if not, check whether colliding node is in its main position or not; | 224 | ** position or not; if it is not, move colliding node to an empty place and |
230 | ** if it is not, move colliding node to an empty place and put new key | 225 | ** put new key in its main position; otherwise (colliding node is in its main |
231 | ** in its main position; otherwise (colliding node is in its main position), | 226 | ** position), new key goes to an empty position. |
232 | ** new key goes to an empty position. | ||
233 | */ | 227 | */ |
234 | TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) { | 228 | static TObject *newkey (lua_State *L, Hash *t, Node *mp, const TObject *key) { |
235 | Node *mp = luaH_mainposition(t, key); | ||
236 | Node *n = mp; | ||
237 | if (!mp) | ||
238 | lua_error(L, "table index is nil"); | ||
239 | do { /* check whether `key' is somewhere in the chain */ | ||
240 | if (luaO_equalObj(key, &n->key)) | ||
241 | return &n->val; /* that's all */ | ||
242 | else n = n->next; | ||
243 | } while (n); | ||
244 | /* `key' not found; must insert it */ | ||
245 | if (ttype(&mp->key) != LUA_TNIL) { /* main position is not free? */ | 229 | if (ttype(&mp->key) != LUA_TNIL) { /* main position is not free? */ |
246 | Node *othern; /* main position of colliding node */ | 230 | Node *othern = luaH_mainposition(t, &mp->key); /* `mp' of colliding node */ |
247 | n = t->firstfree; /* get a free place */ | 231 | Node *n = t->firstfree; /* get a free place */ |
248 | /* is colliding node out of its main position? (can only happens if | 232 | if (othern != mp) { /* is colliding node out of its main position? */ |
249 | its position is after "firstfree") */ | ||
250 | if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) { | ||
251 | /* yes; move colliding node into free position */ | 233 | /* yes; move colliding node into free position */ |
252 | while (othern->next != mp) othern = othern->next; /* find previous */ | 234 | while (othern->next != mp) othern = othern->next; /* find previous */ |
253 | othern->next = n; /* redo the chain with `n' in place of `mp' */ | 235 | othern->next = n; /* redo the chain with `n' in place of `mp' */ |
@@ -273,25 +255,57 @@ TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) { | |||
273 | } | 255 | } |
274 | 256 | ||
275 | 257 | ||
276 | TObject *luaH_setint (lua_State *L, Hash *t, int key) { | 258 | static TObject *luaH_setany (lua_State *L, Hash *t, const TObject *key) { |
277 | TObject index; | 259 | Node *mp = luaH_mainposition(t, key); |
278 | ttype(&index) = LUA_TNUMBER; | 260 | Node *n = mp; |
279 | nvalue(&index) = key; | 261 | if (!mp) |
280 | return luaH_set(L, t, &index); | 262 | lua_error(L, "table index is nil"); |
263 | do { /* check whether `key' is somewhere in the chain */ | ||
264 | if (luaO_equalObj(key, &n->key)) | ||
265 | return &n->val; /* that's all */ | ||
266 | else n = n->next; | ||
267 | } while (n); | ||
268 | return newkey(L, t, mp, key); /* `key' not found; must insert it */ | ||
269 | } | ||
270 | |||
271 | |||
272 | TObject *luaH_setnum (lua_State *L, Hash *t, lua_Number key) { | ||
273 | TObject kobj; | ||
274 | Node *mp = hashnum(t, key); | ||
275 | Node *n = mp; | ||
276 | do { /* check whether `key' is somewhere in the chain */ | ||
277 | if (nvalue(&n->key) == key && ttype(&n->key) == LUA_TNUMBER) | ||
278 | return &n->val; /* that's all */ | ||
279 | else n = n->next; | ||
280 | } while (n); | ||
281 | /* `key' not found; must insert it */ | ||
282 | ttype(&kobj) = LUA_TNUMBER; | ||
283 | nvalue(&kobj) = key; | ||
284 | return newkey(L, t, mp, &kobj); | ||
281 | } | 285 | } |
282 | 286 | ||
283 | 287 | ||
284 | void luaH_setstrnum (lua_State *L, Hash *t, TString *key, lua_Number val) { | 288 | TObject *luaH_setstr (lua_State *L, Hash *t, TString *key) { |
285 | TObject *value, index; | 289 | TObject kobj; |
286 | ttype(&index) = LUA_TSTRING; | 290 | Node *mp = hashstr(t, key); |
287 | tsvalue(&index) = key; | 291 | Node *n = mp; |
288 | value = luaH_set(L, t, &index); | 292 | do { /* check whether `key' is somewhere in the chain */ |
289 | ttype(value) = LUA_TNUMBER; | 293 | if (tsvalue(&n->key) == key && ttype(&n->key) == LUA_TSTRING) |
290 | nvalue(value) = val; | 294 | return &n->val; /* that's all */ |
295 | else n = n->next; | ||
296 | } while (n); | ||
297 | /* `key' not found; must insert it */ | ||
298 | ttype(&kobj) = LUA_TSTRING; | ||
299 | tsvalue(&kobj) = key; | ||
300 | return newkey(L, t, mp, &kobj); | ||
291 | } | 301 | } |
292 | 302 | ||
293 | 303 | ||
294 | const TObject *luaH_getglobal (lua_State *L, const char *name) { | 304 | TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) { |
295 | return luaH_getstr(L->gt, luaS_new(L, name)); | 305 | switch (ttype(key)) { |
306 | case LUA_TNUMBER: return luaH_setnum(L, t, nvalue(key)); | ||
307 | case LUA_TSTRING: return luaH_setstr(L, t, tsvalue(key)); | ||
308 | default: return luaH_setany(L, t, key); | ||
309 | } | ||
296 | } | 310 | } |
297 | 311 | ||