diff options
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 191 |
1 files changed, 104 insertions, 87 deletions
@@ -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 | ||