]> git.lizzy.rs Git - rust.git/commitdiff
use `String::with_capacity` in `format!`
authorMichał Krasnoborski <mkrdln@gmail.com>
Fri, 27 Jan 2017 03:51:24 +0000 (04:51 +0100)
committerMichał Krasnoborski <mkrdln@gmail.com>
Sat, 28 Jan 2017 00:50:05 +0000 (01:50 +0100)
src/libcollections/fmt.rs
src/libcore/fmt/mod.rs
src/libcoretest/fmt/mod.rs
src/libcoretest/lib.rs

index 883417e9f4ec76c90bcc9f3e4dbc7dc32dafe1cb..bd74848a01d8362f150b23701c6af47359f10f8f 100644 (file)
 /// [format!]: ../macro.format.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn format(args: Arguments) -> string::String {
-    let mut output = string::String::new();
+    let capacity = args.estimated_capacity();
+    let mut output = string::String::with_capacity(capacity);
     let _ = output.write_fmt(args);
     output
 }
index 2ba7d6e8bd1ac4d885c9edc336762950f8fe1ff6..ed9c5d3337f04dde8fc58f9e188699ba3c010b92 100644 (file)
@@ -265,6 +265,34 @@ pub fn new_v1_formatted(pieces: &'a [&'a str],
             args: args
         }
     }
+
+    /// Estimates the length of the formatted text.
+    ///
+    /// This is intended to be used for setting initial `String` capacity
+    /// when using `format!`. Note: this is neither the lower nor upper bound.
+    #[doc(hidden)] #[inline]
+    #[unstable(feature = "fmt_internals", reason = "internal to format_args!",
+               issue = "0")]
+    pub fn estimated_capacity(&self) -> usize {
+        // Using wrapping arithmetics in this function, because
+        // wrong result is highly unlikely and doesn't cause unsafety.
+        use ::num::Wrapping as W;
+
+        let pieces_length: W<usize> = self.pieces.iter()
+            .map(|x| W(x.len())).sum();
+
+        // If they are any arguments to format, the string will most likely
+        // double in size. So we're pre-doubling it here.
+        let multiplier = if self.args.is_empty() { W(1) } else { W(2) };
+
+        let capacity = multiplier * pieces_length;
+        if multiplier == W(2) && (W(1)..W(8)).contains(capacity) {
+            // Allocations smaller than 8 don't really make sense for String.
+            8
+        } else {
+            capacity.0
+        }
+    }
 }
 
 /// This structure represents a safely precompiled version of a format string
index ed33596e1c264562ab48e0c3d4ef3e11912172e6..71b3a440f7beaf8f873f154020913aa3e8a3969f 100644 (file)
@@ -28,3 +28,11 @@ fn test_pointer_formats_data_pointer() {
     assert_eq!(format!("{:p}", s), format!("{:p}", s.as_ptr()));
     assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr()));
 }
+
+#[test]
+fn test_estimated_capacity() {
+    assert_eq!(format_args!("{}", "").estimated_capacity(), 0);
+    assert_eq!(format_args!("Hello").estimated_capacity(), 5);
+    assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16);
+    assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 16);
+}
index ee47b510ee0744fef35629d023734c4782a78c7a..fed5b86c369e8d5985af91ff8b3b83c996122b0d 100644 (file)
@@ -34,6 +34,7 @@
 #![feature(ordering_chaining)]
 #![feature(result_unwrap_or_default)]
 #![feature(ptr_unaligned)]
+#![feature(fmt_internals)]
 
 extern crate core;
 extern crate test;