Skip to content

Commit

Permalink
use String::with_capacity in format!
Browse files Browse the repository at this point in the history
  • Loading branch information
krdln committed Jan 28, 2017
1 parent 8430042 commit e74b55b
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/libcollections/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,8 @@ use string;
/// [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
}
28 changes: 28 additions & 0 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,34 @@ 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 {
// 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
Expand Down
8 changes: 8 additions & 0 deletions src/libcoretest/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
1 change: 1 addition & 0 deletions src/libcoretest/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#![feature(ordering_chaining)]
#![feature(result_unwrap_or_default)]
#![feature(ptr_unaligned)]
#![feature(fmt_internals)]

extern crate core;
extern crate test;
Expand Down

0 comments on commit e74b55b

Please sign in to comment.