diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-13 13:12:33 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-13 13:12:33 -0300 |
commit | 6d042a178fba32d10ec23c98fb2fd284397ccddc (patch) | |
tree | f68f9c48a5c3832e929f1317bfd83750ca13b17d /lauxlib.c | |
parent | eabf425c76e0089eb88e102e2a44d8c8a37bc213 (diff) | |
download | lua-6d042a178fba32d10ec23c98fb2fd284397ccddc.tar.gz lua-6d042a178fba32d10ec23c98fb2fd284397ccddc.tar.bz2 lua-6d042a178fba32d10ec23c98fb2fd284397ccddc.zip |
Auxiliary buffer uses external strings
The buffer system from the auxiliary library reuses its buffer
as external memory when closing long strings.
Diffstat (limited to 'lauxlib.c')
-rw-r--r-- | lauxlib.c | 54 |
1 files changed, 38 insertions, 16 deletions
@@ -470,18 +470,27 @@ typedef struct UBox { | |||
470 | } UBox; | 470 | } UBox; |
471 | 471 | ||
472 | 472 | ||
473 | /* Resize the buffer used by a box. Optimize for the common case of | ||
474 | ** resizing to the old size. (For instance, __gc will resize the box | ||
475 | ** to 0 even after it was closed. 'pushresult' may also resize it to a | ||
476 | ** final size that is equal to the one set when the buffer was created.) | ||
477 | */ | ||
473 | static void *resizebox (lua_State *L, int idx, size_t newsize) { | 478 | static void *resizebox (lua_State *L, int idx, size_t newsize) { |
474 | void *ud; | ||
475 | lua_Alloc allocf = lua_getallocf(L, &ud); | ||
476 | UBox *box = (UBox *)lua_touserdata(L, idx); | 479 | UBox *box = (UBox *)lua_touserdata(L, idx); |
477 | void *temp = allocf(ud, box->box, box->bsize, newsize); | 480 | if (box->bsize == newsize) /* not changing size? */ |
478 | if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ | 481 | return box->box; /* keep the buffer */ |
479 | lua_pushliteral(L, "not enough memory"); | 482 | else { |
480 | lua_error(L); /* raise a memory error */ | 483 | void *ud; |
484 | lua_Alloc allocf = lua_getallocf(L, &ud); | ||
485 | void *temp = allocf(ud, box->box, box->bsize, newsize); | ||
486 | if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ | ||
487 | lua_pushliteral(L, "not enough memory"); | ||
488 | lua_error(L); /* raise a memory error */ | ||
489 | } | ||
490 | box->box = temp; | ||
491 | box->bsize = newsize; | ||
492 | return temp; | ||
481 | } | 493 | } |
482 | box->box = temp; | ||
483 | box->bsize = newsize; | ||
484 | return temp; | ||
485 | } | 494 | } |
486 | 495 | ||
487 | 496 | ||
@@ -526,15 +535,15 @@ static void newbox (lua_State *L) { | |||
526 | 535 | ||
527 | /* | 536 | /* |
528 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' | 537 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' |
529 | ** bytes. (The test for "not big enough" also gets the case when the | 538 | ** bytes plus one for a terminating zero. (The test for "not big enough" |
530 | ** computation of 'newsize' overflows.) | 539 | ** also gets the case when the computation of 'newsize' overflows.) |
531 | */ | 540 | */ |
532 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { | 541 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { |
533 | size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ | 542 | size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ |
534 | if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ | 543 | if (l_unlikely(MAX_SIZET - sz - 1 < B->n)) /* overflow in (B->n + sz + 1)? */ |
535 | return luaL_error(B->L, "buffer too large"); | 544 | return luaL_error(B->L, "buffer too large"); |
536 | if (newsize < B->n + sz) /* not big enough? */ | 545 | if (newsize < B->n + sz + 1) /* not big enough? */ |
537 | newsize = B->n + sz; | 546 | newsize = B->n + sz + 1; |
538 | return newsize; | 547 | return newsize; |
539 | } | 548 | } |
540 | 549 | ||
@@ -594,9 +603,22 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { | |||
594 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | 603 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { |
595 | lua_State *L = B->L; | 604 | lua_State *L = B->L; |
596 | checkbufferlevel(B, -1); | 605 | checkbufferlevel(B, -1); |
597 | lua_pushlstring(L, B->b, B->n); | 606 | if (!buffonstack(B)) /* using static buffer? */ |
598 | if (buffonstack(B)) | 607 | lua_pushlstring(L, B->b, B->n); /* save result as regular string */ |
608 | else { /* reuse buffer already allocated */ | ||
609 | UBox *box = (UBox *)lua_touserdata(L, -1); | ||
610 | void *ud; | ||
611 | lua_Alloc allocf = lua_getallocf(L, &ud); /* function to free buffer */ | ||
612 | size_t len = B->n; /* final string length */ | ||
613 | char *s; | ||
614 | resizebox(L, -1, len + 1); /* adjust box size to content size */ | ||
615 | s = (char*)box->box; /* final buffer address */ | ||
616 | s[len] = '\0'; /* add ending zero */ | ||
617 | /* clear box, as 'lua_pushextlstring' will take control over buffer */ | ||
618 | box->bsize = 0; box->box = NULL; | ||
619 | lua_pushextlstring(L, s, len, allocf, ud); | ||
599 | lua_closeslot(L, -2); /* close the box */ | 620 | lua_closeslot(L, -2); /* close the box */ |
621 | } | ||
600 | lua_remove(L, -2); /* remove box or placeholder from the stack */ | 622 | lua_remove(L, -2); /* remove box or placeholder from the stack */ |
601 | } | 623 | } |
602 | 624 | ||