summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-02-04 15:54:09 +0000
committerDavid Mitchell <davem@iabyn.com>2017-02-04 16:03:17 +0000
commit90c3aa01208e3c5b9ab464a058bbd2f6ebda4ff4 (patch)
tree373a937ecdab4101d4a2edd697b526cb3eaf689e /pp_ctl.c
parente452bf1c9e9f30813b1f289188a6e8b0894575ba (diff)
downloadperl-90c3aa01208e3c5b9ab464a058bbd2f6ebda4ff4.tar.gz
pp_formline: simplify growing of PL_formtarget
There's some reasonably complex logic to try and second guess how much space to allocate or reallocate for the output buffer (some of which is my doing from 2011, 26e935cfa6e7). This commit removes most of this and now just does: initially, grow the buffer by the size of the format. If any further growing is needed later on (e.g. after a utf8 upgrade or due to @*) then just grow as needed. This may give less optimal growing in edge cases ( i.e. repeated smaller grows rather than one big grow), but the old code was often guessing wrong anyway. This commit also makes it *always* check whether PL_formtarget needs growing when about to append data to it, which is safer.
Diffstat (limited to 'pp_ctl.c')
-rw-r--r--pp_ctl.c35
1 files changed, 11 insertions, 24 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index 799baa456b..0b759035ad 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -482,7 +482,6 @@ PP(pp_formline)
NV value;
bool gotsome = FALSE; /* seen at least one non-blank item on this line */
STRLEN len; /* length of current sv */
- STRLEN linemax; /* estimate of output size in bytes */
bool item_is_utf8 = FALSE;
bool targ_is_utf8 = FALSE;
const char *fmt;
@@ -505,10 +504,11 @@ PP(pp_formline)
SvTAINTED_on(PL_formtarget);
if (DO_UTF8(PL_formtarget))
targ_is_utf8 = TRUE;
- /* this is an initial estimate of how much output buffer space
- * to allocate. It may be exceeded later */
- linemax = (SvCUR(formsv) * (IN_BYTES ? 1 : 3) + 1);
- t = SvGROW(PL_formtarget, len + linemax + 1);
+ /* Usually the output data will be the same size as the format,
+ * so this is a good first guess. Later on, @* or utf8 upgrades
+ * may trigger further growing.
+ */
+ t = SvGROW(PL_formtarget, len + SvCUR(formsv) + 1);
/* XXX from now onwards, SvCUR(PL_formtarget) is invalid */
t += len;
f = SvPV_const(formsv, len);
@@ -761,14 +761,12 @@ PP(pp_formline)
* if trans, translate certain characters during the copy */
{
U8 *tmp = NULL;
- STRLEN grow = 0;
+ STRLEN cur = t - SvPVX_const(PL_formtarget);
- SvCUR_set(PL_formtarget,
- t - SvPVX_const(PL_formtarget));
+ SvCUR_set(PL_formtarget, cur);
if (targ_is_utf8 && !item_is_utf8) {
source = tmp = bytes_to_utf8(source, &to_copy);
- grow = to_copy;
} else {
if (item_is_utf8 && !targ_is_utf8) {
U8 *s;
@@ -776,14 +774,10 @@ PP(pp_formline)
a problem we have a simple solution for.
Don't need get magic. */
sv_utf8_upgrade_nomg(PL_formtarget);
+ cur = SvCUR(PL_formtarget); /* may have changed */
targ_is_utf8 = TRUE;
/* re-calculate linemark */
s = (U8*)SvPVX(PL_formtarget);
- /* the bytes we initially allocated to append the
- * whole line may have been gobbled up during the
- * upgrade, so allocate a whole new line's worth
- * for safety */
- grow = linemax;
while (linemark--)
s += UTF8SKIP(s);
linemark = s - (U8*)SvPVX(PL_formtarget);
@@ -791,17 +785,10 @@ PP(pp_formline)
/* Easy. They agree. */
assert (item_is_utf8 == targ_is_utf8);
}
- if (!trans)
- /* @* and ^* are the only things that can exceed
- * the linemax, so grow by the output size, plus
- * a whole new form's worth in case of any further
- * output */
- grow = linemax + to_copy;
- if (grow)
- SvGROW(PL_formtarget, SvCUR(PL_formtarget) + grow + 1);
- t = SvPVX(PL_formtarget) + SvCUR(PL_formtarget);
+ t = SvGROW(PL_formtarget, cur + to_copy + 1) + cur;
Copy(source, t, to_copy, char);
+
if (trans) {
/* blank out ~ or control chars, depending on trans.
* works on bytes not chars, so relies on not
@@ -817,7 +804,7 @@ PP(pp_formline)
}
t += to_copy;
- SvCUR_set(PL_formtarget, SvCUR(PL_formtarget) + to_copy);
+ SvCUR_set(PL_formtarget, cur + to_copy);
if (tmp)
Safefree(tmp);
break;