File tree 4 files changed +39
-1
lines changed
4 files changed +39
-1
lines changed Original file line number Diff line number Diff line change @@ -539,7 +539,8 @@ use string;
539
539
/// [format!]: ../macro.format.html
540
540
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
541
541
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) ;
543
544
let _ = output. write_fmt ( args) ;
544
545
output
545
546
}
Original file line number Diff line number Diff line change @@ -265,6 +265,34 @@ impl<'a> Arguments<'a> {
265
265
args : args
266
266
}
267
267
}
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
+ }
268
296
}
269
297
270
298
/// 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() {
28
28
assert_eq ! ( format!( "{:p}" , s) , format!( "{:p}" , s. as_ptr( ) ) ) ;
29
29
assert_eq ! ( format!( "{:p}" , b) , format!( "{:p}" , b. as_ptr( ) ) ) ;
30
30
}
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 34
34
#![ feature( ordering_chaining) ]
35
35
#![ feature( result_unwrap_or_default) ]
36
36
#![ feature( ptr_unaligned) ]
37
+ #![ feature( fmt_internals) ]
37
38
38
39
extern crate core;
39
40
extern crate test;
You can’t perform that action at this time.
0 commit comments