File tree Expand file tree Collapse file tree 4 files changed +39
-1
lines changed Expand file tree Collapse file tree 4 files changed +39
-1
lines changed Original file line number Diff line number Diff line change @@ -539,7 +539,8 @@ use string;
539539/// [format!]: ../macro.format.html
540540#[ stable( feature = "rust1" , since = "1.0.0" ) ]
541541pub 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}
Original file line number Diff line number Diff 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
Original file line number Diff line number Diff 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+ }
Original file line number Diff line number Diff line change 3434#![ feature( ordering_chaining) ]
3535#![ feature( result_unwrap_or_default) ]
3636#![ feature( ptr_unaligned) ]
37+ #![ feature( fmt_internals) ]
3738
3839extern crate core;
3940extern crate test;
You can’t perform that action at this time.
0 commit comments