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 /lauxlib.c | |
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)
Diffstat (limited to 'lauxlib.c')
-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 | ||