diff options
| author | bors <bors@rust-lang.org> | 2017-02-03 20:09:36 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-02-03 20:09:36 +0000 |
| commit | 86d9ed6c82c6745fec46b9ecf2fa91be7924dd16 (patch) | |
| tree | 00bac1c7b714a59f1e4f230a64cb5427de2b62eb /src/libcore | |
| parent | aed6410a7b0f15dc68536e0735787436526ba395 (diff) | |
| parent | 0267529681e2fac6ef4560afe7d8d439d04e6303 (diff) | |
| download | rust-86d9ed6c82c6745fec46b9ecf2fa91be7924dd16.tar.gz rust-86d9ed6c82c6745fec46b9ecf2fa91be7924dd16.zip | |
Auto merge of #39356 - krdln:format-with-capacity, r=aturon
Use `String::with_capacity` in `format!`
Add an `Arguments::estimated_capacity` to estimate the length of formatted text and use it in `std::fmt::format` as the initial capacity of the buffer.
The capacity is calculated based on the literal parts of format string, see the details in the implementation.
Some benches:
```rust
empty: format!("{}", black_box(""))
literal: format!("Literal")
long: format!("Hello Hello Hello Hello, {}!", black_box("world"))
long_rev: format!("{}, hello hello hello hello!", black_box("world"))
long_rev_2: format!("{}{}, hello hello hello hello!", 1, black_box("world"))
short: format!("Hello, {}!", black_box("world"))
short_rev: format!("{}, hello!", black_box("world"))
short_rev_2: format!("{}{}, hello!", 1, black_box("world"))
surround: format!("aaaaa{}ccccc{}eeeee", black_box("bbbbb"), black_box("eeeee"))
two_spaced: format!("{} {}", black_box("bbbbb"), black_box("eeeee"))
worst_case: format!("{} a long piece...", black_box("and even longer argument. not sure why it has to be so long"))
```
```
empty 25 28 3 12.00%
literal 35 29 -6 -17.14%
long 80 46 -34 -42.50%
long_rev 79 45 -34 -43.04%
long_rev_2 111 66 -45 -40.54%
short 73 46 -27 -36.99%
short_rev 74 76 2 2.70%
short_rev_2 107 108 1 0.93%
surround 142 65 -77 -54.23%
two_spaced 111 115 4 3.60%
worst_case 89 101 12 13.48%
```
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/fmt/mod.rs | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 2ba7d6e8bd1..a989f914db6 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -265,6 +265,32 @@ impl<'a> Arguments<'a> { 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 { + let pieces_length: usize = self.pieces.iter() + .map(|x| x.len()).sum(); + + if self.args.is_empty() { + pieces_length + } else if self.pieces[0] == "" && pieces_length < 16 { + // If the format string starts with an argument, + // don't preallocate anything, unless length + // of pieces is significant. + 0 + } else { + // There are some arguments, so any additional push + // will reallocate the string. To avoid that, + // we're "pre-doubling" the capacity here. + pieces_length.checked_mul(2).unwrap_or(0) + } + } } /// This structure represents a safely precompiled version of a format string |
