diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-01-05 16:20:51 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-01-05 16:20:51 -0200 |
commit | e2498e079e4636217e89f0b28844c4b5df4f8793 (patch) | |
tree | da82e007f0e8153985323c2bdb190811f79e0c57 | |
parent | 65726f3e2e226f6a350a5dba643c13c8edd34965 (diff) | |
download | lua-e2498e079e4636217e89f0b28844c4b5df4f8793.tar.gz lua-e2498e079e4636217e89f0b28844c4b5df4f8793.tar.bz2 lua-e2498e079e4636217e89f0b28844c4b5df4f8793.zip |
change in hash algorithm so that it does not need empty slot
(tables can be 100% full)
-rw-r--r-- | lgc.c | 9 | ||||
-rw-r--r-- | lobject.h | 6 | ||||
-rw-r--r-- | lparser.c | 4 | ||||
-rw-r--r-- | lstate.c | 5 | ||||
-rw-r--r-- | lstate.h | 3 | ||||
-rw-r--r-- | ltable.c | 191 | ||||
-rw-r--r-- | ltable.h | 4 | ||||
-rw-r--r-- | ltests.c | 7 | ||||
-rw-r--r-- | lvm.c | 4 |
9 files changed, 125 insertions, 108 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.18 2004/12/06 17:53:42 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.19 2004/12/13 12:15:11 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -63,7 +63,7 @@ | |||
63 | 63 | ||
64 | 64 | ||
65 | static void removeentry (Node *n) { | 65 | static void removeentry (Node *n) { |
66 | setnilvalue(gval(n)); /* remove corresponding value ... */ | 66 | lua_assert(ttisnil(gval(n))); |
67 | if (iscollectable(gkey(n))) | 67 | if (iscollectable(gkey(n))) |
68 | setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ | 68 | setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ |
69 | } | 69 | } |
@@ -162,7 +162,6 @@ static int traversetable (global_State *g, Table *h) { | |||
162 | const TValue *mode; | 162 | const TValue *mode; |
163 | if (h->metatable) | 163 | if (h->metatable) |
164 | markobject(g, h->metatable); | 164 | markobject(g, h->metatable); |
165 | lua_assert(h->lsizenode || h->node == g->dummynode); | ||
166 | mode = gfasttm(g, h->metatable, TM_MODE); | 165 | mode = gfasttm(g, h->metatable, TM_MODE); |
167 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | 166 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ |
168 | weakkey = (strchr(svalue(mode), 'k') != NULL); | 167 | weakkey = (strchr(svalue(mode), 'k') != NULL); |
@@ -368,8 +367,10 @@ static void cleartable (GCObject *l) { | |||
368 | while (i--) { | 367 | while (i--) { |
369 | Node *n = gnode(h, i); | 368 | Node *n = gnode(h, i); |
370 | if (!ttisnil(gval(n)) && /* non-empty entry? */ | 369 | if (!ttisnil(gval(n)) && /* non-empty entry? */ |
371 | (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) | 370 | (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { |
371 | setnilvalue(gval(n)); /* remove value ... */ | ||
372 | removeentry(n); /* remove entry from table */ | 372 | removeentry(n); /* remove entry from table */ |
373 | } | ||
373 | } | 374 | } |
374 | l = h->gclist; | 375 | l = h->gclist; |
375 | } | 376 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 2.7 2004/11/01 15:06:50 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.8 2004/12/04 18:10:22 roberto Exp roberto $ |
3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -330,7 +330,7 @@ typedef struct Table { | |||
330 | struct Table *metatable; | 330 | struct Table *metatable; |
331 | TValue *array; /* array part */ | 331 | TValue *array; /* array part */ |
332 | Node *node; | 332 | Node *node; |
333 | Node *firstfree; /* this position is free; all positions after it are full */ | 333 | Node *lastfree; /* any free position is before this position */ |
334 | GCObject *gclist; | 334 | GCObject *gclist; |
335 | int sizearray; /* size of `array' array */ | 335 | int sizearray; /* size of `array' array */ |
336 | } Table; | 336 | } Table; |
@@ -351,6 +351,8 @@ typedef struct Table { | |||
351 | 351 | ||
352 | extern const TValue luaO_nilobject; | 352 | extern const TValue luaO_nilobject; |
353 | 353 | ||
354 | #define ceillog2(x) (luaO_log2((x)-1) + 1) | ||
355 | |||
354 | int luaO_log2 (unsigned int x); | 356 | int luaO_log2 (unsigned int x); |
355 | int luaO_int2fb (unsigned int x); | 357 | int luaO_int2fb (unsigned int x); |
356 | int luaO_fb2int (int x); | 358 | int luaO_fb2int (int x); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.c,v 2.11 2004/12/07 18:31:16 roberto Exp $ | 2 | ** $Id: lparser.c,v 2.12 2005/01/04 15:55:12 roberto Exp roberto $ |
3 | ** Lua Parser | 3 | ** Lua Parser |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -547,7 +547,7 @@ static void constructor (LexState *ls, expdesc *t) { | |||
547 | check_match(ls, '}', '{', line); | 547 | check_match(ls, '}', '{', line); |
548 | lastlistfield(fs, &cc); | 548 | lastlistfield(fs, &cc); |
549 | SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ | 549 | SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ |
550 | SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh+1)); /* set initial table size */ | 550 | SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ |
551 | } | 551 | } |
552 | 552 | ||
553 | /* }====================================================================== */ | 553 | /* }====================================================================== */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.c,v 2.19 2004/12/13 12:15:11 roberto Exp $ | 2 | ** $Id: lstate.c,v 2.20 2005/01/04 15:55:12 roberto Exp roberto $ |
3 | ** Global State | 3 | ** Global State |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -189,9 +189,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
189 | g->grayagain = NULL; | 189 | g->grayagain = NULL; |
190 | g->weak = NULL; | 190 | g->weak = NULL; |
191 | g->tmudata = NULL; | 191 | g->tmudata = NULL; |
192 | setnilvalue(gkey(g->dummynode)); | ||
193 | setnilvalue(gval(g->dummynode)); | ||
194 | gnext(g->dummynode) = NULL; | ||
195 | g->totalbytes = sizeof(LG); | 192 | g->totalbytes = sizeof(LG); |
196 | g->gcpace = GCDIV; | 193 | g->gcpace = GCDIV; |
197 | g->incgc = 1; | 194 | g->incgc = 1; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 2.9 2004/12/06 17:53:42 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.10 2004/12/13 12:15:11 roberto Exp roberto $ |
3 | ** Global State | 3 | ** Global State |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -90,7 +90,6 @@ typedef struct global_State { | |||
90 | lua_CFunction panic; /* to be called in unprotected errors */ | 90 | lua_CFunction panic; /* to be called in unprotected errors */ |
91 | TValue _registry; | 91 | TValue _registry; |
92 | struct lua_State *mainthread; | 92 | struct lua_State *mainthread; |
93 | Node dummynode[1]; /* common node array for all empty tables */ | ||
94 | TString *tmname[TM_N]; /* array with tag-method names */ | 93 | TString *tmname[TM_N]; /* array with tag-method names */ |
95 | } global_State; | 94 | } global_State; |
96 | 95 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 2.12 2004/12/04 18:10:22 roberto Exp $ | 2 | ** $Id: ltable.c,v 2.13 2005/01/04 15:55:12 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 | */ |
@@ -68,6 +68,13 @@ | |||
68 | #define numints cast(int, sizeof(lua_Number)/sizeof(int)) | 68 | #define numints cast(int, sizeof(lua_Number)/sizeof(int)) |
69 | 69 | ||
70 | 70 | ||
71 | |||
72 | const Node luaH_dummynode = { | ||
73 | {{NULL}, LUA_TNIL}, /* value */ | ||
74 | {{NULL}, LUA_TNIL, NULL} /* key */ | ||
75 | }; | ||
76 | |||
77 | |||
71 | /* | 78 | /* |
72 | ** hash for lua_Numbers | 79 | ** hash for lua_Numbers |
73 | */ | 80 | */ |
@@ -176,31 +183,32 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
176 | */ | 183 | */ |
177 | 184 | ||
178 | 185 | ||
179 | static void computesizes (int nums[], int ntotal, int *narray, int *nhash) { | 186 | static int computesizes (int nums[], int *narray) { |
180 | int i; | 187 | int i; |
181 | int a = nums[0]; /* number of elements smaller than 2^i */ | 188 | int twotoi; /* 2^i */ |
182 | int na = a; /* number of elements to go to array part */ | 189 | int a = 0; /* number of elements smaller than 2^i */ |
183 | int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */ | 190 | int na = 0; /* number of elements to go to array part */ |
184 | for (i = 1; a < *narray && *narray >= twoto(i-1); i++) { | 191 | int n = 0; /* optimal size for array part */ |
192 | for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { | ||
185 | if (nums[i] > 0) { | 193 | if (nums[i] > 0) { |
186 | a += nums[i]; | 194 | a += nums[i]; |
187 | if (a >= twoto(i-1)) { /* more than half elements in use? */ | 195 | if (a > twotoi/2) { /* more than half elements present? */ |
188 | n = i; | 196 | n = twotoi; /* optimal size (till now) */ |
189 | na = a; | 197 | na = a; /* all elements smaller than n will go to array part */ |
190 | } | 198 | } |
191 | } | 199 | } |
200 | if (a == *narray) break; /* all elements already counted */ | ||
192 | } | 201 | } |
193 | lua_assert(na <= *narray && *narray <= ntotal); | 202 | *narray = n; |
194 | *nhash = ntotal - na; | 203 | lua_assert(*narray/2 <= na && na <= *narray); |
195 | *narray = (n == -1) ? 0 : twoto(n); | 204 | return na; |
196 | lua_assert(na <= *narray && na >= *narray/2); | ||
197 | } | 205 | } |
198 | 206 | ||
199 | 207 | ||
200 | static int countint (const TValue *key, int *nums) { | 208 | static int countint (const TValue *key, int *nums) { |
201 | int k = arrayindex(key); | 209 | int k = arrayindex(key); |
202 | if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ | 210 | if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ |
203 | nums[luaO_log2(k-1)+1]++; /* count as such */ | 211 | nums[ceillog2(k)]++; /* count as such */ |
204 | return 1; | 212 | return 1; |
205 | } | 213 | } |
206 | else | 214 | else |
@@ -208,40 +216,44 @@ static int countint (const TValue *key, int *nums) { | |||
208 | } | 216 | } |
209 | 217 | ||
210 | 218 | ||
211 | static void numuse (const Table *t, int *narray, int *nhash, const TValue *ek) { | 219 | static int numusearray (const Table *t, int *nums) { |
212 | int nums[MAXBITS+1]; | 220 | int lg; |
213 | int i, lg; | 221 | int ttlg; /* 2^lg */ |
214 | int totaluse = 0; | 222 | int ause = 0; /* summation of `nums' */ |
215 | /* count elements in array part */ | 223 | int i = 1; /* count to traverse all array keys */ |
216 | for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ | 224 | for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ |
217 | int ttlg = twoto(lg); /* 2^lg */ | 225 | int lc = 0; /* counter */ |
218 | if (ttlg > t->sizearray) { | 226 | int lim = ttlg; |
219 | ttlg = t->sizearray; | 227 | if (lim > t->sizearray) { |
220 | if (i >= ttlg) break; | 228 | lim = t->sizearray; /* adjust upper limit */ |
229 | if (i > lim) | ||
230 | break; /* no more elements to count */ | ||
221 | } | 231 | } |
222 | nums[lg] = 0; | 232 | /* count elements in range (2^(lg-1), 2^lg] */ |
223 | for (; i<ttlg; i++) { | 233 | for (; i <= lim; i++) { |
224 | if (!ttisnil(&t->array[i])) { | 234 | if (!ttisnil(&t->array[i-1])) |
225 | nums[lg]++; | 235 | lc++; |
226 | totaluse++; | ||
227 | } | ||
228 | } | 236 | } |
237 | nums[lg] += lc; | ||
238 | ause += lc; | ||
229 | } | 239 | } |
230 | for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */ | 240 | return ause; |
231 | *narray = totaluse; /* all previous uses were in array part */ | 241 | } |
232 | /* count elements in hash part */ | 242 | |
233 | i = sizenode(t); | 243 | |
244 | static int numusehash (const Table *t, int *nums, int *pnasize) { | ||
245 | int totaluse = 0; /* total number of elements */ | ||
246 | int ause = 0; /* summation of `nums' */ | ||
247 | int i = sizenode(t); | ||
234 | while (i--) { | 248 | while (i--) { |
235 | Node *n = &t->node[i]; | 249 | Node *n = &t->node[i]; |
236 | if (!ttisnil(gval(n))) { | 250 | if (!ttisnil(gval(n))) { |
237 | *narray += countint(key2tval(n), nums); | 251 | ause += countint(key2tval(n), nums); |
238 | totaluse++; | 252 | totaluse++; |
239 | } | 253 | } |
240 | } | 254 | } |
241 | /* count extra key */ | 255 | *pnasize += ause; |
242 | *narray += countint(ek, nums); | 256 | return totaluse; |
243 | totaluse++; | ||
244 | computesizes(nums, totaluse, narray, nhash); | ||
245 | } | 257 | } |
246 | 258 | ||
247 | 259 | ||
@@ -254,18 +266,18 @@ static void setarrayvector (lua_State *L, Table *t, int size) { | |||
254 | } | 266 | } |
255 | 267 | ||
256 | 268 | ||
257 | static void setnodevector (lua_State *L, Table *t, int lsize) { | 269 | static void setnodevector (lua_State *L, Table *t, int size) { |
258 | int i; | 270 | int lsize; |
259 | int size = twoto(lsize); | 271 | if (size == 0) { /* no elements to hash part? */ |
260 | if (lsize > MAXBITS) | 272 | t->node = cast(Node *, &luaH_dummynode); /* use common `dummynode' */ |
261 | luaG_runerror(L, "table overflow"); | 273 | lsize = 0; |
262 | if (lsize == 0) { /* no elements to hash part? */ | ||
263 | t->node = G(L)->dummynode; /* use common `dummynode' */ | ||
264 | lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */ | ||
265 | lua_assert(ttisnil(gval(t->node))); | ||
266 | lua_assert(gnext(t->node) == NULL); /* (`dummynode' must be empty) */ | ||
267 | } | 274 | } |
268 | else { | 275 | else { |
276 | int i; | ||
277 | lsize = ceillog2(size); | ||
278 | if (lsize > MAXBITS) | ||
279 | luaG_runerror(L, "table overflow"); | ||
280 | size = twoto(lsize); | ||
269 | t->node = luaM_newvector(L, size, Node); | 281 | t->node = luaM_newvector(L, size, Node); |
270 | for (i=0; i<size; i++) { | 282 | for (i=0; i<size; i++) { |
271 | gnext(&t->node[i]) = NULL; | 283 | gnext(&t->node[i]) = NULL; |
@@ -274,31 +286,19 @@ static void setnodevector (lua_State *L, Table *t, int lsize) { | |||
274 | } | 286 | } |
275 | } | 287 | } |
276 | t->lsizenode = cast(lu_byte, lsize); | 288 | t->lsizenode = cast(lu_byte, lsize); |
277 | t->firstfree = gnode(t, size-1); /* first free position to be used */ | 289 | t->lastfree = gnode(t, size); /* all positions are free */ |
278 | } | 290 | } |
279 | 291 | ||
280 | 292 | ||
281 | static void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { | 293 | static void resize (lua_State *L, Table *t, int nasize, int nhsize) { |
282 | int i; | 294 | int i; |
283 | int oldasize = t->sizearray; | 295 | int oldasize = t->sizearray; |
284 | int oldhsize = t->lsizenode; | 296 | int oldhsize = t->lsizenode; |
285 | Node *nold; | 297 | Node *nold = t->node; /* save old hash ... */ |
286 | Node temp[1]; | ||
287 | if (oldhsize) | ||
288 | nold = t->node; /* save old hash ... */ | ||
289 | else { /* old hash is `dummynode' */ | ||
290 | lua_assert(t->node == G(L)->dummynode); | ||
291 | temp[0] = t->node[0]; /* copy it to `temp' */ | ||
292 | nold = temp; | ||
293 | setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */ | ||
294 | setnilvalue(gval(G(L)->dummynode)); | ||
295 | lua_assert(gnext(G(L)->dummynode) == NULL); | ||
296 | } | ||
297 | if (nasize > oldasize) /* array part must grow? */ | 298 | if (nasize > oldasize) /* array part must grow? */ |
298 | setarrayvector(L, t, nasize); | 299 | setarrayvector(L, t, nasize); |
299 | /* create new hash part with appropriate size */ | 300 | /* create new hash part with appropriate size */ |
300 | setnodevector(L, t, nhsize); | 301 | setnodevector(L, t, nhsize); |
301 | /* re-insert elements */ | ||
302 | if (nasize < oldasize) { /* array part must shrink? */ | 302 | if (nasize < oldasize) { /* array part must shrink? */ |
303 | t->sizearray = nasize; | 303 | t->sizearray = nasize; |
304 | /* re-insert elements from vanishing slice */ | 304 | /* re-insert elements from vanishing slice */ |
@@ -309,28 +309,39 @@ static void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { | |||
309 | /* shrink array */ | 309 | /* shrink array */ |
310 | luaM_reallocvector(L, t->array, oldasize, nasize, TValue); | 310 | luaM_reallocvector(L, t->array, oldasize, nasize, TValue); |
311 | } | 311 | } |
312 | /* re-insert elements in hash part */ | 312 | /* re-insert elements from hash part */ |
313 | for (i = twoto(oldhsize) - 1; i >= 0; i--) { | 313 | for (i = twoto(oldhsize) - 1; i >= 0; i--) { |
314 | Node *old = nold+i; | 314 | Node *old = nold+i; |
315 | if (!ttisnil(gval(old))) | 315 | if (!ttisnil(gval(old))) |
316 | setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); | 316 | setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); |
317 | } | 317 | } |
318 | if (oldhsize) | 318 | if (nold != &luaH_dummynode) |
319 | luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ | 319 | luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ |
320 | } | 320 | } |
321 | 321 | ||
322 | 322 | ||
323 | void luaH_resizearray (lua_State *L, Table *t, int nasize) { | 323 | void luaH_resizearray (lua_State *L, Table *t, int nasize) { |
324 | luaH_resize(L, t, nasize, t->lsizenode); | 324 | int nsize = (t->node == &luaH_dummynode) ? 0 : sizenode(t); |
325 | resize(L, t, nasize, nsize); | ||
325 | } | 326 | } |
326 | 327 | ||
327 | 328 | ||
328 | static void rehash (lua_State *L, Table *t, const TValue *ek) { | 329 | static void rehash (lua_State *L, Table *t, const TValue *ek) { |
329 | int nasize, nhsize; | 330 | int nasize, na; |
330 | /* compute new sizes for array and hash parts */ | 331 | int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ |
331 | numuse(t, &nasize, &nhsize, ek); | 332 | int i; |
333 | int totaluse; | ||
334 | for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ | ||
335 | nasize = numusearray(t, nums); /* count keys in array part */ | ||
336 | totaluse = nasize; /* all those keys are integer keys */ | ||
337 | totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ | ||
338 | /* count extra key */ | ||
339 | nasize += countint(ek, nums); | ||
340 | totaluse++; | ||
341 | /* compute new size for array part */ | ||
342 | na = computesizes(nums, &nasize); | ||
332 | /* resize the table to new computed sizes */ | 343 | /* resize the table to new computed sizes */ |
333 | luaH_resize(L, t, nasize, luaO_log2(nhsize)+1); | 344 | resize(L, t, nasize, totaluse - na); |
334 | } | 345 | } |
335 | 346 | ||
336 | 347 | ||
@@ -349,21 +360,30 @@ Table *luaH_new (lua_State *L, int narray, int nhash) { | |||
349 | t->array = NULL; | 360 | t->array = NULL; |
350 | t->sizearray = 0; | 361 | t->sizearray = 0; |
351 | t->lsizenode = 0; | 362 | t->lsizenode = 0; |
352 | t->node = NULL; | 363 | t->node = cast(Node *, &luaH_dummynode); |
353 | setarrayvector(L, t, narray); | 364 | setarrayvector(L, t, narray); |
354 | setnodevector(L, t, luaO_log2(nhash)+1); | 365 | setnodevector(L, t, nhash); |
355 | return t; | 366 | return t; |
356 | } | 367 | } |
357 | 368 | ||
358 | 369 | ||
359 | void luaH_free (lua_State *L, Table *t) { | 370 | void luaH_free (lua_State *L, Table *t) { |
360 | if (t->lsizenode) | 371 | if (t->node != &luaH_dummynode) |
361 | luaM_freearray(L, t->node, sizenode(t), Node); | 372 | luaM_freearray(L, t->node, sizenode(t), Node); |
362 | luaM_freearray(L, t->array, t->sizearray, TValue); | 373 | luaM_freearray(L, t->array, t->sizearray, TValue); |
363 | luaM_free(L, t); | 374 | luaM_free(L, t); |
364 | } | 375 | } |
365 | 376 | ||
366 | 377 | ||
378 | static Node *getfreepos (lua_State *L, Table *t) { | ||
379 | while (t->lastfree-- > t->node) { | ||
380 | if (ttisnil(gkey(t->lastfree))) | ||
381 | return t->lastfree; | ||
382 | } | ||
383 | return NULL; /* could not find a free place */ | ||
384 | } | ||
385 | |||
386 | |||
367 | 387 | ||
368 | /* | 388 | /* |
369 | ** inserts a new key into a hash table; first, check whether key's main | 389 | ** inserts a new key into a hash table; first, check whether key's main |
@@ -374,10 +394,15 @@ void luaH_free (lua_State *L, Table *t) { | |||
374 | */ | 394 | */ |
375 | static TValue *newkey (lua_State *L, Table *t, const TValue *key) { | 395 | static TValue *newkey (lua_State *L, Table *t, const TValue *key) { |
376 | Node *mp = luaH_mainposition(t, key); | 396 | Node *mp = luaH_mainposition(t, key); |
377 | if (!ttisnil(gval(mp))) { /* main position is not free? */ | 397 | if (!ttisnil(gval(mp)) || mp == &luaH_dummynode) { |
378 | /* `mp' of colliding node */ | 398 | Node *othern; |
379 | Node *othern = luaH_mainposition(t, key2tval(mp)); | 399 | Node *n = getfreepos(L, t); /* get a free place */ |
380 | Node *n = t->firstfree; /* get a free place */ | 400 | if (n == NULL) { /* cannot find a free place? */ |
401 | rehash(L, t, key); /* grow table */ | ||
402 | return luaH_set(L, t, key); /* re-insert key into grown table */ | ||
403 | } | ||
404 | lua_assert(n != &luaH_dummynode); | ||
405 | othern = luaH_mainposition(t, key2tval(mp)); | ||
381 | if (othern != mp) { /* is colliding node out of its main position? */ | 406 | if (othern != mp) { /* is colliding node out of its main position? */ |
382 | /* yes; move colliding node into free position */ | 407 | /* yes; move colliding node into free position */ |
383 | while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ | 408 | while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ |
@@ -396,15 +421,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { | |||
396 | gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; | 421 | gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; |
397 | luaC_barriert(L, t, key); | 422 | luaC_barriert(L, t, key); |
398 | lua_assert(ttisnil(gval(mp))); | 423 | lua_assert(ttisnil(gval(mp))); |
399 | for (;;) { /* correct `firstfree' */ | 424 | return gval(mp); |
400 | if (ttisnil(gkey(t->firstfree))) | ||
401 | return gval(mp); /* OK; table still has a free place */ | ||
402 | else if (t->firstfree == t->node) break; /* cannot decrement from here */ | ||
403 | else (t->firstfree)--; | ||
404 | } | ||
405 | /* no more free places; must create one */ | ||
406 | rehash(L, t, key); /* grow table */ | ||
407 | return luaH_set(L, t, key); /* re-insert in new table */ | ||
408 | } | 425 | } |
409 | 426 | ||
410 | 427 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.h,v 2.3 2004/10/06 18:34:16 roberto Exp roberto $ | 2 | ** $Id: ltable.h,v 2.4 2005/01/04 15:55:12 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 | */ |
@@ -18,6 +18,8 @@ | |||
18 | #define key2tval(n) (cast(const TValue *, gkey(n))) | 18 | #define key2tval(n) (cast(const TValue *, gkey(n))) |
19 | 19 | ||
20 | 20 | ||
21 | extern const Node luaH_dummynode; | ||
22 | |||
21 | const TValue *luaH_getnum (Table *t, int key); | 23 | const TValue *luaH_getnum (Table *t, int key); |
22 | TValue *luaH_setnum (lua_State *L, Table *t, int key); | 24 | TValue *luaH_setnum (lua_State *L, Table *t, int key); |
23 | const TValue *luaH_getstr (Table *t, TString *key); | 25 | const TValue *luaH_getstr (Table *t, TString *key); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltests.c,v 2.14 2004/10/06 18:34:16 roberto Exp $ | 2 | ** $Id: ltests.c,v 2.15 2004/11/01 15:06:50 roberto Exp roberto $ |
3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -200,7 +200,6 @@ static void checktable (global_State *g, Table *h) { | |||
200 | GCObject *hgc = obj2gco(h); | 200 | GCObject *hgc = obj2gco(h); |
201 | if (h->metatable) | 201 | if (h->metatable) |
202 | checkobjref(g, hgc, h->metatable); | 202 | checkobjref(g, hgc, h->metatable); |
203 | lua_assert(h->lsizenode || h->node == g->dummynode); | ||
204 | mode = gfasttm(g, h->metatable, TM_MODE); | 203 | mode = gfasttm(g, h->metatable, TM_MODE); |
205 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | 204 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ |
206 | weakkey = (strchr(svalue(mode), 'k') != NULL); | 205 | weakkey = (strchr(svalue(mode), 'k') != NULL); |
@@ -542,8 +541,8 @@ static int table_query (lua_State *L) { | |||
542 | t = hvalue(obj_at(L, 1)); | 541 | t = hvalue(obj_at(L, 1)); |
543 | if (i == -1) { | 542 | if (i == -1) { |
544 | lua_pushinteger(L, t->sizearray); | 543 | lua_pushinteger(L, t->sizearray); |
545 | lua_pushinteger(L, sizenode(t)); | 544 | lua_pushinteger(L, t->node == &luaH_dummynode ? 0 : sizenode(t)); |
546 | lua_pushinteger(L, t->firstfree - t->node); | 545 | lua_pushinteger(L, t->lastfree - t->node); |
547 | } | 546 | } |
548 | else if (i < t->sizearray) { | 547 | else if (i < t->sizearray) { |
549 | lua_pushinteger(L, i); | 548 | lua_pushinteger(L, i); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.18 2004/12/03 20:35:33 roberto Exp $ | 2 | ** $Id: lvm.c,v 2.19 2005/01/04 15:55:12 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -462,7 +462,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { | |||
462 | case OP_NEWTABLE: { | 462 | case OP_NEWTABLE: { |
463 | int b = GETARG_B(i); | 463 | int b = GETARG_B(i); |
464 | int c = GETARG_C(i); | 464 | int c = GETARG_C(i); |
465 | sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c) - 1)); | 465 | sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); |
466 | L->ci->savedpc = pc; | 466 | L->ci->savedpc = pc; |
467 | luaC_checkGC(L); /***/ | 467 | luaC_checkGC(L); /***/ |
468 | base = L->base; | 468 | base = L->base; |