There is a simplification and optimization for __vfprintf() from android
pointed out by tedu:

https://github.com/aosp-mirror/platform_bionic/commit/5305a4d4a723b06494b93f2df81733b83a0c46d3

If we only support UTF-8 and ASCII, we do not need complicated multibyte
decoding to recognize a '%' in the format string.

In his commit message, enh claims that there is a 10x speedup. In my own
benchmarking on amd64, a speedup between 1.5x and 5x seems to be more
realistic. The code does get significantly simpler, so I think it might
be worth it.

The android commit has lots of style noise. There is a second part to it
that fixes some missing error checking in vfwprintf similar to some of
schwarze's fixes in vfprintf.c r1.71.  I'll send that one out in a
second mail as it's completely independent.

Do we want this?

Index: lib/libc/stdio/vfprintf.c
===================================================================
RCS file: /var/cvs/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.77
diff -u -p -r1.77 vfprintf.c
--- lib/libc/stdio/vfprintf.c   29 Aug 2016 12:20:57 -0000      1.77
+++ lib/libc/stdio/vfprintf.c   14 Nov 2017 08:07:27 -0000
@@ -279,8 +279,6 @@ __vfprintf(FILE *fp, const char *fmt0, _
        int width;              /* width from format (%8d), or 0 */
        int prec;               /* precision from format; <0 for N/A */
        char sign;              /* sign prefix (' ', '+', '-', or \0) */
-       wchar_t wc;
-       mbstate_t ps;
 #ifdef FLOATING_POINT
        /*
         * We can decompose the printed representation of floating
@@ -481,25 +479,13 @@ __vfprintf(FILE *fp, const char *fmt0, _
        convbuf = NULL;
 #endif
 
-       memset(&ps, 0, sizeof(ps));
        /*
         * Scan the format for conversions (`%' character).
         */
        for (;;) {
-               size_t len;
+               for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+                       continue;
 
-               cp = fmt;
-               while ((len = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) != 0) {
-                       if (len == (size_t)-1 || len == (size_t)-2) {
-                               ret = -1;
-                               goto error;
-                       }
-                       fmt += len;
-                       if (wc == '%') {
-                               fmt--;
-                               break;
-                       }
-               }
                if (fmt != cp) {
                        ptrdiff_t m = fmt - cp;
                        if (m < 0 || m > INT_MAX - ret)
@@ -507,7 +493,7 @@ __vfprintf(FILE *fp, const char *fmt0, _
                        PRINT(cp, m);
                        ret += m;
                }
-               if (len == 0)
+               if (ch == '\0')
                        goto done;
                fmt++;          /* skip over '%' */
 
@@ -852,7 +838,9 @@ fp_common:
                        xdigs = xdigs_lower;
                        ox[1] = 'x';
                        goto nosign;
-               case 's':
+               case 's': {
+                       size_t len;
+
 #ifdef PRINTF_WIDE_CHAR
                        if (flags & LONGINT) {
                                wchar_t *wcp;
@@ -893,6 +881,7 @@ fp_common:
                                goto overflow;
                        size = (int)len;
                        sign = '\0';
+                       }
                        break;
                case 'U':
                        flags |= LONGINT;
@@ -1156,8 +1145,6 @@ __find_arguments(const char *fmt0, va_li
        int tablemax;           /* largest used index in table */
        int nextarg;            /* 1-based argument index */
        int ret = 0;            /* return value */
-       wchar_t wc;
-       mbstate_t ps;
 
        /*
         * Add an argument type to the table, expanding if necessary.
@@ -1211,25 +1198,14 @@ __find_arguments(const char *fmt0, va_li
        tablemax = 0;
        nextarg = 1;
        memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
-       memset(&ps, 0, sizeof(ps));
 
        /*
         * Scan the format for conversions (`%' character).
         */
        for (;;) {
-               size_t len;
-
-               cp = fmt;
-               while ((len = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) != 0) {
-                       if (len == (size_t)-1 || len == (size_t)-2)
-                               return (-1);
-                       fmt += len;
-                       if (wc == '%') {
-                               fmt--;
-                               break;
-                       }
-               }
-               if (len == 0)
+               for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+                       continue;
+               if (ch == '\0')
                        goto done;
                fmt++;          /* skip over '%' */
 

Reply via email to