Skip to content

Commit e74b55b

Browse files
committed
use String::with_capacity in format!
1 parent 8430042 commit e74b55b

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

src/libcollections/fmt.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ use string;
539539
/// [format!]: ../macro.format.html
540540
#[stable(feature = "rust1", since = "1.0.0")]
541541
pub fn format(args: Arguments) -> string::String {
542-
let mut output = string::String::new();
542+
let capacity = args.estimated_capacity();
543+
let mut output = string::String::with_capacity(capacity);
543544
let _ = output.write_fmt(args);
544545
output
545546
}

src/libcore/fmt/mod.rs

+28
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,34 @@ impl<'a> Arguments<'a> {
265265
args: args
266266
}
267267
}
268+
269+
/// Estimates the length of the formatted text.
270+
///
271+
/// This is intended to be used for setting initial `String` capacity
272+
/// when using `format!`. Note: this is neither the lower nor upper bound.
273+
#[doc(hidden)] #[inline]
274+
#[unstable(feature = "fmt_internals", reason = "internal to format_args!",
275+
issue = "0")]
276+
pub fn estimated_capacity(&self) -> usize {
277+
// Using wrapping arithmetics in this function, because
278+
// wrong result is highly unlikely and doesn't cause unsafety.
279+
use ::num::Wrapping as W;
280+
281+
let pieces_length: W<usize> = self.pieces.iter()
282+
.map(|x| W(x.len())).sum();
283+
284+
// If they are any arguments to format, the string will most likely
285+
// double in size. So we're pre-doubling it here.
286+
let multiplier = if self.args.is_empty() { W(1) } else { W(2) };
287+
288+
let capacity = multiplier * pieces_length;
289+
if multiplier == W(2) && (W(1)..W(8)).contains(capacity) {
290+
// Allocations smaller than 8 don't really make sense for String.
291+
8
292+
} else {
293+
capacity.0
294+
}
295+
}
268296
}
269297

270298
/// This structure represents a safely precompiled version of a format string

src/libcoretest/fmt/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,11 @@ fn test_pointer_formats_data_pointer() {
2828
assert_eq!(format!("{:p}", s), format!("{:p}", s.as_ptr()));
2929
assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr()));
3030
}
31+
32+
#[test]
33+
fn test_estimated_capacity() {
34+
assert_eq!(format_args!("{}", "").estimated_capacity(), 0);
35+
assert_eq!(format_args!("Hello").estimated_capacity(), 5);
36+
assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16);
37+
assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 16);
38+
}

src/libcoretest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#![feature(ordering_chaining)]
3535
#![feature(result_unwrap_or_default)]
3636
#![feature(ptr_unaligned)]
37+
#![feature(fmt_internals)]
3738

3839
extern crate core;
3940
extern crate test;

0 commit comments

Comments
 (0)