This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Perl_sv_vcatpvfn_flags: remove "%.Ng" special-case
authorDavid Mitchell <davem@iabyn.com>
Sat, 20 May 2017 11:07:23 +0000 (12:07 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 7 Jun 2017 08:11:03 +0000 (09:11 +0100)
This function has special-case handling for the formats "%.0f" and
"%.NNg", to speed things up. This special-casing appears twice,
once near the top of the function for where the format matches exactly
"%.0f" or "%.Ng" (N is 1..99), and once again in the main loop of the
function, where it handles those format elements embedded in the larger
format: "....%.0f..." and "....%.Ng..." (N > 0).

The problem with the "%.Ng" code is that it isn't as robust as the more
general "....%.Ng..." code - in particular the latter checks for a
locale-dependent radix-point when determining needed buffer size.

This commit removes the "%.Ng" special-cased code but leaves the
"....%.Ng..." special-cased code. It makes the former about 7% slower
compared to the situation at the start of this branch. (Part of the effort
in this branch has been to make the "....%.Ng..." code faster, so that
there's less of an overall performance hit by removing "%.Ng").

sv.c

diff --git a/sv.c b/sv.c
index 0e4bdba..0520ac0 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -11843,42 +11843,20 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
     }
 
 #if !defined(USE_LONG_DOUBLE) && !defined(USE_QUADMATH)
-    /* special-case "%.0f" and "%.<number>g" */
-    if ( !args && 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');
-
-       /* XXX: Why do this `svix < svmax` test? Couldn't we just
-          format the first argument and WARN_REDUNDANT if svmax > 1?
-          Munged by Nicholas Clark in v5.13.0-209-g95ea86d */
-       if (pp + 1 == pat + patlen && svix < svmax) {
-           const NV nv = SvNV(*svargs);
-            if (LIKELY(!Perl_isinfnan(nv))) {
-                if (*pp == 'g') {
-                    /* Add check for digits != 0 because it seems that some
-                       Gconvert's are buggy in this case, and we don't yet
-                       have a Configure test for this.  */
-                    if (digits && digits < sizeof(ebuf) - NV_DIG - 10) {
-                        /* 0, point, slack */
-                        STORE_LC_NUMERIC_SET_TO_NEEDED();
-                        SNPRINTF_G(nv, ebuf, sizeof(ebuf), digits);
-                        sv_catpv_nomg(sv, ebuf);
-                        if (*ebuf)     /* May return an empty string for digits==0 */
-                            return;
-                    }
-                } else if (!digits) {
-                    STRLEN l;
+    /* special-case "%.0f" */
+    if (    !args
+         && patlen == 4
+         && pat[0] == '%' && pat[1] == '.' && pat[2] == '0' && pat[3] == 'f'
+         && svmax > 0)
+    {
+        const NV nv = SvNV(*svargs);
+        if (LIKELY(!Perl_isinfnan(nv))) {
+            STRLEN l;
+            char *p;
 
-                    if ((p = F0convert(nv, ebuf + sizeof ebuf, &l))) {
-                        sv_catpvn_nomg(sv, p, l);
-                        return;
-                    }
-                }
+            if ((p = F0convert(nv, ebuf + sizeof ebuf, &l))) {
+                sv_catpvn_nomg(sv, p, l);
+                return;
             }
        }
     }