From: Ilya Zakharevich <ilya@math.berkeley.edu>
Date: Mon, 3 Nov 2003 20:27:39 +0000 (-0800)
Subject: [PATCH 5.8.2 @21574] sprintf() painfully slow
X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4151a5feffa8bdd67c09edf6ade78431e8079f67;p=p5sagit%2Fp5-mst-13.2.git

[PATCH 5.8.2 @21574] sprintf() painfully slow
Date: Mon, 3 Nov 2003 20:27:39 -0800
Message-ID: <20031104042739.GA1697@math.berkeley.edu>

Subject: Re: [PATCH 5.8.2 @21574] sprintf() painfully slow
From: Ilya Zakharevich <nospam-abuse@ilyaz.org>
Date: Mon, 3 Nov 2003 20:57:48 -0800
Message-ID: <20031104045748.GA1826@math.berkeley.edu>

p4raw-id: //depot/perl@21694
---

diff --git a/sv.c b/sv.c
index b31a876..6293937 100644
--- a/sv.c
+++ b/sv.c
@@ -8532,6 +8532,33 @@ S_expect_number(pTHX_ char** pattern)
 }
 #define EXPECT_NUMBER(pattern, var) (var = S_expect_number(aTHX_ &pattern))
 
+static char *
+F0convert(NV nv, char *endbuf, STRLEN *len)
+{
+    int neg = nv < 0;
+    UV uv;
+    char *p = endbuf;
+
+    if (neg)
+	nv = -nv;
+    if (nv < UV_MAX) {
+	nv += 0.5;
+	uv = nv;
+	if (uv & 1 && uv == nv)
+	    uv--;			/* Round to even */
+	do {
+	    unsigned dig = uv % 10;
+	    *--p = '0' + dig;
+	} while (uv /= 10);
+	if (neg)
+	    *--p = '-';
+	*len = endbuf - p;
+	return p;
+    }
+    return Nullch;
+}
+
+
 /*
 =for apidoc sv_vcatpvfn
 
@@ -8559,6 +8586,12 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     bool has_utf8; /* has the result utf8? */
     bool pat_utf8; /* the pattern is in utf8? */
     SV *nsv = Nullsv;
+    /* Times 4: a decimal digit takes more than 3 binary digits.
+     * NV_DIG: mantissa takes than many decimal digits.
+     * Plus 32: Playing safe. */
+    char ebuf[IV_DIG * 4 + NV_DIG + 32];
+    /* large enough for "%#.#f" --chip */
+    /* what about long double NVs? --jhi */
 
     has_utf8 = pat_utf8 = DO_UTF8(sv);
 
@@ -8594,6 +8627,42 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 	}
     }
 
+    /* special-case "%.<number>[gf]" */
+    if ( patlen <= 5 && pat[0] == '%' && pat[1] == '.'
+	 && (pat[patlen-1] == 'g' || pat[patlen-1] == 'f') ) {
+	unsigned digits = 0;
+	const char *pp;
+
+	pp = pat + 2;
+	while (*pp >= '0' && *pp <= '9')
+	    digits = 10 * digits + (*pp++ - '0');
+	if (pp - pat == patlen - 1) {
+	    NV nv;
+
+	    if (args)
+		nv = (NV)va_arg(*args, double);
+	    else if (svix < svmax)
+		nv = SvNV(*svargs);
+	    else
+		return;
+	    if (*pp == 'g') {
+		if (digits < sizeof(ebuf) - NV_DIG - 10) { /* 0, point, slack */
+		    Gconvert((double)nv, digits, 0, ebuf);
+		    sv_catpv(sv, ebuf);
+		    if (*ebuf)	/* May return an empty string for digits==0 */
+			return;
+		}
+	    } else if (!digits) {
+		STRLEN l;
+
+		if ((p = F0convert(nv, ebuf + sizeof ebuf, &l))) {
+		    sv_catpvn(sv, p, l);
+		    return;
+		}
+	    }
+	}
+    }
+
     if (!args && svix < svmax && DO_UTF8(*svargs))
 	has_utf8 = TRUE;
 
@@ -8625,13 +8694,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
 	char *eptr = Nullch;
 	STRLEN elen = 0;
-	/* Times 4: a decimal digit takes more than 3 binary digits.
-	 * NV_DIG: mantissa takes than many decimal digits.
-	 * Plus 32: Playing safe. */
-	char ebuf[IV_DIG * 4 + NV_DIG + 32];
-	/* large enough for "%#.#f" --chip */
-	/* what about long double NVs? --jhi */
-
 	SV *vecsv = Nullsv;
 	U8 *vecstr = Null(U8*);
 	STRLEN veclen = 0;
@@ -9291,6 +9353,17 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 		PL_efloatbuf[0] = '\0';
 	    }
 
+	    if ( !(width || left || plus || alt) && fill != '0'
+		 && has_precis && intsize != 'q' ) {	/* Shortcuts */
+		if ( c == 'g') {
+		    Gconvert((double)nv, precis, 0, PL_efloatbuf);
+		    if (*PL_efloatbuf)	/* May return an empty string for digits==0 */
+			goto float_converted;
+		} else if ( c == 'f' && !precis) {
+		    if ((eptr = F0convert(nv, ebuf + sizeof ebuf, &elen)))
+			break;
+		}
+	    }
 	    eptr = ebuf + sizeof ebuf;
 	    *--eptr = '\0';
 	    *--eptr = c;
@@ -9335,6 +9408,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #else
 	    (void)sprintf(PL_efloatbuf, eptr, nv);
 #endif
+	float_converted:
 	    eptr = PL_efloatbuf;
 	    elen = strlen(PL_efloatbuf);
 	    break;