about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2021-05-16 21:31:18 -0400
committerMark Rousskov <mark.simulacrum@gmail.com>2021-05-17 09:29:02 -0400
commit80ac15f667c32b1e441cffaa3237cae2990cc152 (patch)
treea86a48b4fa77c0b767b6a70073532b0e9366367a
parent2a245f40a19c9a60b3be33c959eb5cfb0ad163c6 (diff)
downloadrust-80ac15f667c32b1e441cffaa3237cae2990cc152.tar.gz
rust-80ac15f667c32b1e441cffaa3237cae2990cc152.zip
Optimize default ToString impl
This avoids a zero-length write_str call, which boils down to a zero-length
memmove and ultimately costs quite a few instructions on some workloads.

This is approximately a 0.33% instruction count win on diesel-check.
-rw-r--r--library/alloc/src/string.rs5
-rw-r--r--library/core/src/fmt/mod.rs32
2 files changed, 26 insertions, 11 deletions
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index e6252452470..ec09595e357 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -2323,9 +2323,10 @@ impl<T: fmt::Display + ?Sized> ToString for T {
     // to try to remove it.
     #[inline]
     default fn to_string(&self) -> String {
-        use fmt::Write;
         let mut buf = String::new();
-        buf.write_fmt(format_args!("{}", self))
+        let mut formatter = core::fmt::Formatter::new(&mut buf);
+        // Bypass format_args!() to avoid write_str with zero-length strs
+        fmt::Display::fmt(self, &mut formatter)
             .expect("a Display implementation returned an error unexpectedly");
         buf
     }
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 87042d95fbe..5cb3c9062fe 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -221,6 +221,28 @@ pub struct Formatter<'a> {
     buf: &'a mut (dyn Write + 'a),
 }
 
+impl<'a> Formatter<'a> {
+    /// Creates a new formatter with default settings.
+    ///
+    /// This can be used as a micro-optimization in cases where a full `Arguments`
+    /// structure (as created by `format_args!`) is not necessary; `Arguments`
+    /// is a little more expensive to use in simple formatting scenarios.
+    ///
+    /// Currently not intended for use outside of the standard library.
+    #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")]
+    #[doc(hidden)]
+    pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> {
+        Formatter {
+            flags: 0,
+            fill: ' ',
+            align: rt::v1::Alignment::Unknown,
+            width: None,
+            precision: None,
+            buf,
+        }
+    }
+}
+
 // NB. Argument is essentially an optimized partially applied formatting function,
 // equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
 
@@ -1075,15 +1097,7 @@ pub trait UpperExp {
 /// [`write!`]: crate::write!
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
-    let mut formatter = Formatter {
-        flags: 0,
-        width: None,
-        precision: None,
-        buf: output,
-        align: rt::v1::Alignment::Unknown,
-        fill: ' ',
-    };
-
+    let mut formatter = Formatter::new(output);
     let mut idx = 0;
 
     match args.fmt {