bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/5] use strchr for simple case of find_char_unquote


From: Paolo Bonzini
Subject: [PATCH 2/5] use strchr for simple case of find_char_unquote
Date: Wed, 2 Nov 2016 17:24:15 +0100

In most cases, find_char_unquote has a single stopchar.  In that
case we can look for it using strchr's optimized implementation.

The resulting speedup on QEMU's noop build is 4.4% (from 14.5 seconds
to 13.8).

* read.c (find_char_unquote): Rename to find_map_unquote.  Replace
with an implementation optimized for the case where the stopchar
is a singleton.  Adjust all callers.
---
 read.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 54 insertions(+), 13 deletions(-)

diff --git a/read.c b/read.c
index 0883100..c2d42d2 100644
--- a/read.c
+++ b/read.c
@@ -153,7 +153,8 @@ static void record_target_var (struct nameseq *filenames, 
char *defn,
 static enum make_word_type get_next_mword (char *buffer, char *delim,
                                            char **startp, unsigned int 
*length);
 static void remove_comments (char *line);
-static char *find_char_unquote (char *string, int map);
+static char *find_map_unquote (char *string, int map);
+static char *find_char_unquote (char *string, int stop);
 static char *unescape_char (char *string, int c);
 
 
@@ -1008,7 +1009,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
         /* Search the line for an unquoted ; that is not after an
            unquoted #.  */
-        cmdleft = find_char_unquote (line, MAP_SEMI|MAP_COMMENT|MAP_VARIABLE);
+        cmdleft = find_map_unquote (line, MAP_SEMI|MAP_COMMENT|MAP_VARIABLE);
         if (cmdleft != 0 && *cmdleft == '#')
           {
             /* We found a comment before a semicolon.  */
@@ -1055,7 +1056,7 @@ eval (struct ebuffer *ebuf, int set_default)
             if (cmdleft == 0)
               {
                 /* Look for a semicolon in the expanded line.  */
-                cmdleft = find_char_unquote (p2, MAP_SEMI);
+                cmdleft = find_char_unquote (p2, ';');
 
                 if (cmdleft != 0)
                   {
@@ -1082,7 +1083,7 @@ eval (struct ebuffer *ebuf, int set_default)
                   }
               }
 
-            colonp = find_char_unquote (p2, MAP_COLON);
+            colonp = find_char_unquote (p2, ':');
 #ifdef HAVE_DOS_PATHS
             /* The drive spec brain-damage strikes again...  */
             /* Note that the only separators of targets in this context
@@ -1091,7 +1092,7 @@ eval (struct ebuffer *ebuf, int set_default)
             while (colonp && (colonp[1] == '/' || colonp[1] == '\\') &&
                    colonp > p2 && isalpha ((unsigned char)colonp[-1]) &&
                    (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0))
-              colonp = find_char_unquote (colonp + 1, MAP_COLON);
+              colonp = find_char_unquote (colonp + 1, ':');
 #endif
             if (colonp != 0)
               break;
@@ -1184,7 +1185,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
         /* This is a normal target, _not_ a target-specific variable.
            Unquote any = in the dependency list.  */
-        find_char_unquote (lb_next, MAP_EQUALS);
+        find_char_unquote (lb_next, '=');
 
         /* Remember the command prefix for this target.  */
         prefix = cmd_prefix;
@@ -1202,7 +1203,7 @@ eval (struct ebuffer *ebuf, int set_default)
             /* Look for a semicolon in the expanded line.  */
             if (cmdleft == 0)
               {
-                cmdleft = find_char_unquote (p2, MAP_SEMI);
+                cmdleft = find_char_unquote (p2, ';');
                 if (cmdleft != 0)
                   *(cmdleft++) = '\0';
               }
@@ -1405,7 +1406,7 @@ remove_comments (char *line)
 {
   char *comment;
 
-  comment = find_char_unquote (line, MAP_COMMENT);
+  comment = find_char_unquote (line, '#');
 
   if (comment != 0)
     /* Cut off the line at the #.  */
@@ -2234,7 +2235,7 @@ record_files (struct nameseq *filenames, const char 
*pattern,
    STOPCHAR _cannot_ be '$' if IGNOREVARS is true.  */
 
 static char *
-find_char_unquote (char *string, int map)
+find_map_unquote (char *string, int map)
 {
   unsigned int string_len = 0;
   char *p = string;
@@ -2315,6 +2316,46 @@ find_char_unquote (char *string, int map)
   return 0;
 }
 
+static char *
+find_char_unquote (char *string, int stop)
+{
+  unsigned int string_len = 0;
+  char *p = string;
+
+  while (1)
+    {
+      p = strchr(p, stop);
+
+      if (!p)
+        return NULL;
+
+      if (p > string && p[-1] == '\\')
+        {
+          /* Search for more backslashes.  */
+          int i = -2;
+          while (&p[i] >= string && p[i] == '\\')
+            --i;
+          ++i;
+          /* Only compute the length if really needed.  */
+          if (string_len == 0)
+            string_len = strlen (string);
+          /* The number of backslashes is now -I.
+             Copy P over itself to swallow half of them.  */
+          memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1);
+          p += i/2;
+          if (i % 2 == 0)
+            /* All the backslashes quoted each other; the STOPCHAR was
+               unquoted.  */
+            return p;
+
+          /* The STOPCHAR was quoted by a backslash.  Look for another.  */
+        }
+      else
+        /* No backslash in sight.  */
+        return p;
+    }
+}
+
 /* Unescape a character in a string.  The string is compressed onto itself.  */
 
 static char *
@@ -2368,7 +2409,7 @@ unescape_char (char *string, int c)
 char *
 find_percent (char *pattern)
 {
-  return find_char_unquote (pattern, MAP_PERCENT);
+  return find_char_unquote (pattern, '%');
 }
 
 /* Search STRING for an unquoted % and handle quoting.  Returns a pointer to
@@ -3072,7 +3113,7 @@ parse_file_seq (char **stringp, unsigned int size, int 
stopmap,
       /* There are names left, so find the end of the next name.
          Throughout this iteration S points to the start.  */
       s = p;
-      p = find_char_unquote (p, stopmap|MAP_VMSCOMMA|MAP_BLANK);
+      p = find_map_unquote (p, stopmap|MAP_VMSCOMMA|MAP_BLANK);
 #ifdef VMS
         /* convert comma separated list to space separated */
       if (p && *p == ',')
@@ -3081,7 +3122,7 @@ parse_file_seq (char **stringp, unsigned int size, int 
stopmap,
 #ifdef _AMIGA
       if (p && STOP_SET (*p, stopmap & MAP_COLON)
           && !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1])))
-        p = find_char_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
+        p = find_map_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
 #endif
 #ifdef HAVE_DOS_PATHS
     /* For DOS paths, skip a "C:\..." or a "C:/..." until we find the
@@ -3091,7 +3132,7 @@ parse_file_seq (char **stringp, unsigned int size, int 
stopmap,
     if (stopmap | MAP_COLON)
       while (p != 0 && !ISSPACE (*p) &&
              (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1]))
-        p = find_char_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
+        p = find_map_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
 #endif
       if (p == 0)
         p = s + strlen (s);
-- 
2.7.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]