diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-12-08 15:28:25 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-12-08 15:28:25 -0200 |
commit | e663a24ab03a54fa221c20a793812e5c5ffdf94f (patch) | |
tree | 8fbd40f779f0eed29d46f26c07e1234fd5df8bae /ltable.c | |
parent | 40f823ec907fd725617e37199199b3ed424bd88c (diff) | |
download | lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.tar.gz lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.tar.bz2 lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.zip |
more freedom in handling memory-allocation errors (not all allocations
automatically raise an error), which allows fixing a bug when resizing
a table.
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 95 |
1 files changed, 63 insertions, 32 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 2.127 2017/11/23 19:29:04 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 2.128 2017/12/07 18:59:52 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 | */ |
@@ -357,15 +357,6 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { | |||
357 | } | 357 | } |
358 | 358 | ||
359 | 359 | ||
360 | static void setarrayvector (lua_State *L, Table *t, unsigned int size) { | ||
361 | unsigned int i; | ||
362 | luaM_reallocvector(L, t->array, t->sizearray, size, TValue); | ||
363 | for (i=t->sizearray; i<size; i++) | ||
364 | setnilvalue(&t->array[i]); | ||
365 | t->sizearray = size; | ||
366 | } | ||
367 | |||
368 | |||
369 | /* | 360 | /* |
370 | ** Creates an array for the hash part of a table with the given | 361 | ** Creates an array for the hash part of a table with the given |
371 | ** size, or reuses the dummy node if size is zero. | 362 | ** size, or reuses the dummy node if size is zero. |
@@ -398,39 +389,79 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
398 | } | 389 | } |
399 | 390 | ||
400 | 391 | ||
401 | void luaH_resize (lua_State *L, Table *t, unsigned int nasize, | 392 | /* |
393 | ** (Re)insert all elements from list 'nodes' into table 't'. | ||
394 | */ | ||
395 | static void reinsert(lua_State *L, Node *nodes, int nsize, Table *t) { | ||
396 | int j; | ||
397 | for (j = nsize - 1; j >= 0; j--) { | ||
398 | Node *old = nodes + j; | ||
399 | if (!ttisnil(gval(old))) { | ||
400 | /* doesn't need barrier/invalidate cache, as entry was | ||
401 | already present in the table */ | ||
402 | TValue k; | ||
403 | getnodekey(L, &k, old); | ||
404 | setobjt2t(L, luaH_set(L, t, &k), gval(old)); | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | |||
410 | /* | ||
411 | ** Resize table 't' for the new given sizes. Both allocations | ||
412 | ** (for the hash part and for the array part) can fail, which | ||
413 | ** creates some subtleties. If the first allocation, for the hash | ||
414 | ** part, fails, an error is raised and that is it. Otherwise, | ||
415 | ** copy the elements in the shrinking part of the array (if it | ||
416 | ** is shrinking) into the new hash. Then it reallocates the array part. | ||
417 | ** If that fails, it frees the new hash part and restores the old hash | ||
418 | ** part (to restore the original state of the table), and then raises | ||
419 | ** the allocation error. Otherwise, initialize the new part of the | ||
420 | ** array (if any) with nils and reinsert the elements in the old | ||
421 | ** hash back into the new parts of the table. | ||
422 | */ | ||
423 | void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | ||
402 | unsigned int nhsize) { | 424 | unsigned int nhsize) { |
403 | unsigned int i; | 425 | unsigned int i; |
404 | int j; | 426 | Node *oldnode = t->node; /* save old hash ... */ |
405 | unsigned int oldasize = t->sizearray; | 427 | Node *oldlastfree = t->lastfree; |
428 | int oldlsizenode = t->lsizenode; | ||
406 | int oldhsize = allocsizenode(t); | 429 | int oldhsize = allocsizenode(t); |
407 | Node *nold = t->node; /* save old hash ... */ | 430 | unsigned int oldasize = t->sizearray; |
408 | if (nasize > oldasize) /* array part must grow? */ | 431 | TValue *newarray; |
409 | setarrayvector(L, t, nasize); | ||
410 | /* create new hash part with appropriate size */ | 432 | /* create new hash part with appropriate size */ |
411 | setnodevector(L, t, nhsize); | 433 | setnodevector(L, t, nhsize); |
412 | if (nasize < oldasize) { /* array part must shrink? */ | 434 | if (newasize < oldasize) { /* will array shrink? */ |
413 | t->sizearray = nasize; | 435 | /* re-insert into the hash the elements from vanishing slice */ |
414 | /* re-insert elements from vanishing slice */ | 436 | t->sizearray = newasize; /* pretend array has new size */ |
415 | for (i=nasize; i<oldasize; i++) { | 437 | for (i = newasize; i < oldasize; i++) { |
416 | if (!ttisnil(&t->array[i])) | 438 | if (!ttisnil(&t->array[i])) |
417 | luaH_setint(L, t, i + 1, &t->array[i]); | 439 | luaH_setint(L, t, i + 1, &t->array[i]); |
418 | } | 440 | } |
419 | /* shrink array */ | 441 | t->sizearray = oldasize; /* restore current size */ |
420 | luaM_reallocvector(L, t->array, oldasize, nasize, TValue); | ||
421 | } | 442 | } |
422 | /* re-insert elements from hash part */ | 443 | /* allocate new array */ |
423 | for (j = oldhsize - 1; j >= 0; j--) { | 444 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); |
424 | Node *old = nold + j; | 445 | if (newarray == NULL && newasize > 0) { /* allocation failed? */ |
425 | if (!ttisnil(gval(old))) { | 446 | if (nhsize > 0) /* not the dummy node? */ |
426 | /* doesn't need barrier/invalidate cache, as entry was | 447 | luaM_freearray(L, t->node, allocsizenode(t)); /* release new hash part */ |
427 | already present in the table */ | 448 | t->node = oldnode; /* restore original hash part */ |
428 | TValue k; getnodekey(L, &k, old); | 449 | t->lastfree = oldlastfree; |
429 | setobjt2t(L, luaH_set(L, t, &k), gval(old)); | 450 | t->lsizenode = oldlsizenode; |
430 | } | 451 | lua_assert(!isdummy(t) == (t->node != dummynode)); |
452 | luaM_error(L); /* error with array unchanged */ | ||
431 | } | 453 | } |
454 | /* allocation ok; initialize new part of the array */ | ||
455 | t->array = newarray; | ||
456 | t->sizearray = newasize; | ||
457 | for (i = oldasize; i < newasize; i++) | ||
458 | setnilvalue(&t->array[i]); | ||
459 | /* re-insert elements from old hash part into new parts */ | ||
460 | reinsert(L, oldnode, oldhsize, t); | ||
461 | /* free old hash */ | ||
432 | if (oldhsize > 0) /* not the dummy node? */ | 462 | if (oldhsize > 0) /* not the dummy node? */ |
433 | luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ | 463 | luaM_freearray(L, oldnode, cast(size_t, oldhsize)); |
464 | lua_assert(!isdummy(t) == (t->node != dummynode)); | ||
434 | } | 465 | } |
435 | 466 | ||
436 | 467 | ||