diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-06-18 11:23:14 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-06-18 11:23:14 -0300 |
| commit | e7f34ad395284b4ad2b53b092aa4576616ede7c5 (patch) | |
| tree | 2f69a023d9047354c115385ca35de0ed17965b85 | |
| parent | a5cbb7c3a7b26d962fd85ff50dc7e0cea84d93af (diff) | |
| download | lua-e7f34ad395284b4ad2b53b092aa4576616ede7c5.tar.gz lua-e7f34ad395284b4ad2b53b092aa4576616ede7c5.tar.bz2 lua-e7f34ad395284b4ad2b53b092aa4576616ede7c5.zip | |
better implementation for buffers (reallocated memory directly
with allocation function; generates much less garbage)
| -rw-r--r-- | lauxlib.c | 60 |
1 files changed, 52 insertions, 8 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp roberto $ | 2 | ** $Id: lauxlib.c,v 1.280 2015/02/03 17:38:24 roberto Exp roberto $ |
| 3 | ** Auxiliary functions for building Lua libraries | 3 | ** Auxiliary functions for building Lua libraries |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -289,7 +289,7 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { | |||
| 289 | if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ | 289 | if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ |
| 290 | return 0; /* leave previous value on top, but return 0 */ | 290 | return 0; /* leave previous value on top, but return 0 */ |
| 291 | lua_pop(L, 1); | 291 | lua_pop(L, 1); |
| 292 | lua_newtable(L); /* create metatable */ | 292 | lua_createtable(L, 0, 2); /* create metatable */ |
| 293 | lua_pushstring(L, tname); | 293 | lua_pushstring(L, tname); |
| 294 | lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ | 294 | lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ |
| 295 | lua_pushvalue(L, -1); | 295 | lua_pushvalue(L, -1); |
| @@ -435,6 +435,47 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, | |||
| 435 | ** ======================================================= | 435 | ** ======================================================= |
| 436 | */ | 436 | */ |
| 437 | 437 | ||
| 438 | /* userdata to box arbitrary data */ | ||
| 439 | typedef struct UBox { | ||
| 440 | void *box; | ||
| 441 | size_t bsize; | ||
| 442 | } UBox; | ||
| 443 | |||
| 444 | |||
| 445 | static void *resizebox (lua_State *L, int idx, size_t newsize) { | ||
| 446 | void *ud; | ||
| 447 | lua_Alloc allocf = lua_getallocf(L, &ud); | ||
| 448 | UBox *box = (UBox *)lua_touserdata(L, idx); | ||
| 449 | void *temp = allocf(ud, box->box, box->bsize, newsize); | ||
| 450 | if (temp == NULL && newsize > 0) { /* allocation error? */ | ||
| 451 | resizebox(L, idx, 0); /* free buffer */ | ||
| 452 | luaL_error(L, "not enough memory for buffer allocation"); | ||
| 453 | } | ||
| 454 | box->box = temp; | ||
| 455 | box->bsize = newsize; | ||
| 456 | return temp; | ||
| 457 | } | ||
| 458 | |||
| 459 | |||
| 460 | static int boxgc (lua_State *L) { | ||
| 461 | resizebox(L, 1, 0); | ||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 466 | static void *newbox (lua_State *L, size_t newsize) { | ||
| 467 | UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); | ||
| 468 | box->box = NULL; | ||
| 469 | box->bsize = 0; | ||
| 470 | if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ | ||
| 471 | lua_pushcfunction(L, boxgc); | ||
| 472 | lua_setfield(L, -2, "__gc"); /* metatalbe.__gc = boxgc */ | ||
| 473 | } | ||
| 474 | lua_setmetatable(L, -2); | ||
| 475 | return resizebox(L, -1, newsize); | ||
| 476 | } | ||
| 477 | |||
| 478 | |||
| 438 | /* | 479 | /* |
| 439 | ** check whether buffer is using a userdata on the stack as a temporary | 480 | ** check whether buffer is using a userdata on the stack as a temporary |
| 440 | ** buffer | 481 | ** buffer |
| @@ -455,11 +496,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { | |||
| 455 | if (newsize < B->n || newsize - B->n < sz) | 496 | if (newsize < B->n || newsize - B->n < sz) |
| 456 | luaL_error(L, "buffer too large"); | 497 | luaL_error(L, "buffer too large"); |
| 457 | /* create larger buffer */ | 498 | /* create larger buffer */ |
| 458 | newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char)); | ||
| 459 | /* move content to new buffer */ | ||
| 460 | memcpy(newbuff, B->b, B->n * sizeof(char)); | ||
| 461 | if (buffonstack(B)) | 499 | if (buffonstack(B)) |
| 462 | lua_remove(L, -2); /* remove old buffer */ | 500 | newbuff = (char *)resizebox(L, -1, newsize); |
| 501 | else { /* no buffer yet */ | ||
| 502 | newbuff = (char *)newbox(L, newsize); | ||
| 503 | memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ | ||
| 504 | } | ||
| 463 | B->b = newbuff; | 505 | B->b = newbuff; |
| 464 | B->size = newsize; | 506 | B->size = newsize; |
| 465 | } | 507 | } |
| @@ -482,8 +524,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { | |||
| 482 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | 524 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { |
| 483 | lua_State *L = B->L; | 525 | lua_State *L = B->L; |
| 484 | lua_pushlstring(L, B->b, B->n); | 526 | lua_pushlstring(L, B->b, B->n); |
| 485 | if (buffonstack(B)) | 527 | if (buffonstack(B)) { |
| 486 | lua_remove(L, -2); /* remove old buffer */ | 528 | resizebox(L, -2, 0); /* delete old buffer */ |
| 529 | lua_remove(L, -2); /* remove its header from the stack */ | ||
| 530 | } | ||
| 487 | } | 531 | } |
| 488 | 532 | ||
| 489 | 533 | ||
