summaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltable.c')
-rw-r--r--ltable.c191
1 files changed, 104 insertions, 87 deletions
diff --git a/ltable.c b/ltable.c
index d9a1ee20..a3a169b7 100644
--- a/ltable.c
+++ b/ltable.c
@@ -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
72const 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
179static void computesizes (int nums[], int ntotal, int *narray, int *nhash) { 186static 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
200static int countint (const TValue *key, int *nums) { 208static 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
211static void numuse (const Table *t, int *narray, int *nhash, const TValue *ek) { 219static 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
244static 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
257static void setnodevector (lua_State *L, Table *t, int lsize) { 269static 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
281static void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { 293static 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
323void luaH_resizearray (lua_State *L, Table *t, int nasize) { 323void 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
328static void rehash (lua_State *L, Table *t, const TValue *ek) { 329static 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
359void luaH_free (lua_State *L, Table *t) { 370void 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
378static 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*/
375static TValue *newkey (lua_State *L, Table *t, const TValue *key) { 395static 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