]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid some unnecessary copying in Fformat etc.
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 26 Sep 2017 23:31:57 +0000 (16:31 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 26 Sep 2017 23:36:43 +0000 (16:36 -0700)
This patch is just for performance; it should not affect behavior.
On my platform, it made the microbenchmark (format "%S" load-path)
run about 45% faster.  It should also speed up calls like (message
"%s" STRING).
* src/callint.c (Fcall_interactively):
* src/dbusbind.c (XD_OBJECT_TO_STRING):
* src/editfns.c (Fmessage, Fmessage_box):
* src/xdisp.c (vadd_to_log, Ftrace_to_stderr):
Use styled_format instead of Fformat or Fformat_message,
to avoid unnecessary copying.
* src/editfns.c (styled_format): New arg NEW_RESULT.
All uses changed.  Reuse an input string if it has the
right value and if !NEW_RESULT.
* src/lisp.h (style_format): New decl.

src/callint.c
src/dbusbind.c
src/editfns.c
src/lisp.h
src/xdisp.c

index 105ec071d077851cebd901c408818de60d906a17..469205cc380dcc1774a63ba7e20487d898796720 100644 (file)
@@ -272,7 +272,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
 {
   /* `args' will contain the array of arguments to pass to the function.
      `visargs' will contain the same list but in a nicer form, so that if we
-     pass it to `Fformat_message' it will be understandable to a human.  */
+     pass it to styled_format it will be understandable to a human.  */
   Lisp_Object *args, *visargs;
   Lisp_Object specs;
   Lisp_Object filter_specs;
@@ -502,10 +502,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
   for (i = 2; *tem; i++)
     {
       visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n"));
-      if (strchr (SSDATA (visargs[1]), '%'))
-       callint_message = Fformat_message (i - 1, visargs + 1);
-      else
-       callint_message = visargs[1];
+      callint_message = styled_format (i - 1, visargs + 1, true, false);
 
       switch (*tem)
        {
index 4a7068416fe11490ea5b6d9b09a760608d57bd53..789aa008611a55d39ebb0e3a315b41632d5414cf 100644 (file)
@@ -237,7 +237,8 @@ static char *
 XD_OBJECT_TO_STRING (Lisp_Object object)
 {
   AUTO_STRING (format, "%s");
-  return SSDATA (CALLN (Fformat, format, object));
+  Lisp_Object args[] = { format, object };
+  return SSDATA (styled_format (ARRAYELTS (args), args, false, false));
 }
 
 #define XD_DBUS_VALIDATE_BUS_ADDRESS(bus)                              \
index 2f8b075817abff6fd750a88f5a6015c3f54fcdb5..ef0374199ccd8ef7cd5d0c03a206a012df2dc30c 100644 (file)
@@ -74,7 +74,6 @@ static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec,
 static long int tm_gmtoff (struct tm *);
 static int tm_diff (struct tm *, struct tm *);
 static void update_buffer_properties (ptrdiff_t, ptrdiff_t);
-static Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool);
 
 #ifndef HAVE_TM_GMTOFF
 # define HAVE_TM_GMTOFF false
@@ -3959,7 +3958,7 @@ usage: (message FORMAT-STRING &rest ARGS)  */)
     }
   else
     {
-      Lisp_Object val = Fformat_message (nargs, args);
+      Lisp_Object val = styled_format (nargs, args, true, false);
       message3 (val);
       return val;
     }
@@ -3985,7 +3984,7 @@ usage: (message-box FORMAT-STRING &rest ARGS)  */)
     }
   else
     {
-      Lisp_Object val = Fformat_message (nargs, args);
+      Lisp_Object val = styled_format (nargs, args, true, false);
       Lisp_Object pane, menu;
 
       pane = list1 (Fcons (build_string ("OK"), Qt));
@@ -4141,7 +4140,7 @@ produced text.
 usage: (format STRING &rest OBJECTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  return styled_format (nargs, args, false);
+  return styled_format (nargs, args, false, true);
 }
 
 DEFUN ("format-message", Fformat_message, Sformat_message, 1, MANY, 0,
@@ -4157,13 +4156,16 @@ and right quote replacement characters are specified by
 usage: (format-message STRING &rest OBJECTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  return styled_format (nargs, args, true);
+  return styled_format (nargs, args, true, true);
 }
 
-/* Implement ‘format-message’ if MESSAGE is true, ‘format’ otherwise.  */
+/* Implement ‘format-message’ if MESSAGE is true, ‘format’ otherwise.
+   If NEW_RESULT, the result is a new string; otherwise, the result
+   may be one of the arguments.  */
 
-static Lisp_Object
-styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
+Lisp_Object
+styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message,
+              bool new_result)
 {
   ptrdiff_t n;         /* The number of the next arg to substitute.  */
   char initial_buffer[4000];
@@ -4193,6 +4195,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
     /* The start and end bytepos in the output string.  */
     ptrdiff_t start, end;
 
+    /* Whether the argument is a newly created string.  */
+    bool_bf new_string : 1;
+
     /* Whether the argument is a string with intervals.  */
     bool_bf intervals : 1;
   } *info;
@@ -4342,7 +4347,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
          memset (&discarded[format0 - format_start], 1,
                  format - format0 - (conversion == '%'));
          if (conversion == '%')
-           goto copy_char;
+           {
+             new_result = true;
+             goto copy_char;
+           }
 
          ++n;
          if (! (n < nargs))
@@ -4352,6 +4360,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
          if (nspec < ispec)
            {
              spec->argument = args[n];
+             spec->new_string = false;
              spec->intervals = false;
              nspec = ispec;
            }
@@ -4369,11 +4378,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
                {
                  Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
                  spec->argument = arg = Fprin1_to_string (arg, noescape);
+                 spec->new_string = true;
                  if (STRING_MULTIBYTE (arg) && ! multibyte)
                    {
                      multibyte = true;
                      goto retry;
                    }
+                 new_result = false;
                }
              conversion = 's';
            }
@@ -4387,6 +4398,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
                      goto retry;
                    }
                  spec->argument = arg = Fchar_to_string (arg);
+                 spec->new_string = true;
                }
 
              if (!EQ (arg, args[n]))
@@ -4409,6 +4421,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
 
          if (conversion == 's')
            {
+             if (format == end && format - format_start == 2
+                 && (!new_result || spec->new_string)
+                 && ! string_intervals (args[0]))
+               return arg;
+
              /* handle case (precision[n] >= 0) */
 
              ptrdiff_t prec = -1;
@@ -4487,6 +4504,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
                  if (string_intervals (arg))
                    spec->intervals = arg_intervals = true;
 
+                 new_result = true;
                  continue;
                }
            }
@@ -4754,6 +4772,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
                    }
                  spec->end = nchars;
 
+                 new_result = true;
                  continue;
                }
            }
@@ -4772,9 +4791,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
                }
              convsrc = format_char == '`' ? uLSQM : uRSQM;
              convbytes = 3;
+             new_result = true;
            }
          else if (format_char == '`' && quoting_style == STRAIGHT_QUOTING_STYLE)
-           convsrc = "'";
+           {
+             convsrc = "'";
+             new_result = true;
+           }
          else
            {
              /* Copy a single character from format to buf.  */
@@ -4798,6 +4821,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
                  int c = BYTE8_TO_CHAR (format_char);
                  convbytes = CHAR_STRING (c, str);
                  convsrc = (char *) str;
+                 new_result = true;
                }
            }
 
@@ -4844,6 +4868,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
   if (bufsize < p - buf)
     emacs_abort ();
 
+  if (! new_result)
+    return args[0];
+
   if (maybe_combine_byte)
     nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf);
   Lisp_Object val = make_specified_string (buf, nchars, p - buf, multibyte);
index c50308244272cf3c0ffbff7e95efe5d8a91bbf77..0c3ca3ae06b77be29d408a786596121d932e80c0 100644 (file)
@@ -3969,6 +3969,7 @@ extern _Noreturn void time_overflow (void);
 extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool);
 extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t,
                                            ptrdiff_t, bool);
+extern Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool, bool);
 extern void init_editfns (bool);
 extern void syms_of_editfns (void);
 
index 141275f15a09e79afd848a1a88a82e0c01a398f4..86164eb9f6fa2376ce6d881b4c3448f177bd60f6 100644 (file)
@@ -10194,7 +10194,7 @@ vadd_to_log (char const *format, va_list ap)
   for (ptrdiff_t i = 1; i <= nargs; i++)
     args[i] = va_arg (ap, Lisp_Object);
   Lisp_Object msg = Qnil;
-  msg = Fformat_message (nargs, args);
+  msg = styled_format (nargs, args, true, false);
 
   ptrdiff_t len = SBYTES (msg) + 1;
   USE_SAFE_ALLOCA;
@@ -19525,7 +19525,7 @@ DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "",
 usage: (trace-to-stderr STRING &rest OBJECTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  Lisp_Object s = Fformat (nargs, args);
+  Lisp_Object s = styled_format (nargs, args, false, false);
   fwrite (SDATA (s), 1, SBYTES (s), stderr);
   return Qnil;
 }