@@ -47,6 +47,8 @@ use core::iter::FusedIterator;
4747#[ cfg( not( no_global_oom_handling) ) ]
4848use core:: iter:: from_fn;
4949#[ cfg( not( no_global_oom_handling) ) ]
50+ use core:: num:: Saturating ;
51+ #[ cfg( not( no_global_oom_handling) ) ]
5052use core:: ops:: Add ;
5153#[ cfg( not( no_global_oom_handling) ) ]
5254use core:: ops:: AddAssign ;
@@ -1097,6 +1099,22 @@ impl String {
10971099 self . vec . extend_from_slice ( string. as_bytes ( ) )
10981100 }
10991101
1102+ #[ inline]
1103+ fn push_str_slice ( & mut self , slice : & [ & str ] ) {
1104+ // use saturating arithmetic to ensure that in the case of an overflow, reserve() throws OOM
1105+ let additional: Saturating < usize > = slice. iter ( ) . map ( |x| Saturating ( x. len ( ) ) ) . sum ( ) ;
1106+ self . reserve ( additional. 0 ) ;
1107+ let ( ptr, len, cap) = core:: mem:: take ( self ) . into_raw_parts ( ) ;
1108+ unsafe {
1109+ let mut dst = ptr. add ( len) ;
1110+ for new in slice {
1111+ core:: ptr:: copy_nonoverlapping ( new. as_ptr ( ) , dst, new. len ( ) ) ;
1112+ dst = dst. add ( new. len ( ) ) ;
1113+ }
1114+ * self = String :: from_raw_parts ( ptr, len + additional. 0 , cap) ;
1115+ }
1116+ }
1117+
11001118 /// Copies elements from `src` range to the end of the string.
11011119 ///
11021120 /// # Panics
@@ -2489,7 +2507,7 @@ impl<'a> Extend<&'a char> for String {
24892507#[ stable( feature = "rust1" , since = "1.0.0" ) ]
24902508impl < ' a > Extend < & ' a str > for String {
24912509 fn extend < I : IntoIterator < Item = & ' a str > > ( & mut self , iter : I ) {
2492- iter . into_iter ( ) . for_each ( move |s| self . push_str ( s ) ) ;
2510+ < I as SpecExtendStr > :: spec_extend_into ( iter , self )
24932511 }
24942512
24952513 #[ inline]
@@ -2498,6 +2516,32 @@ impl<'a> Extend<&'a str> for String {
24982516 }
24992517}
25002518
2519+ #[ cfg( not( no_global_oom_handling) ) ]
2520+ trait SpecExtendStr {
2521+ fn spec_extend_into ( self , s : & mut String ) ;
2522+ }
2523+
2524+ #[ cfg( not( no_global_oom_handling) ) ]
2525+ impl < ' a , T : IntoIterator < Item = & ' a str > > SpecExtendStr for T {
2526+ default fn spec_extend_into ( self , target : & mut String ) {
2527+ self . into_iter ( ) . for_each ( move |s| target. push_str ( s) ) ;
2528+ }
2529+ }
2530+
2531+ #[ cfg( not( no_global_oom_handling) ) ]
2532+ impl SpecExtendStr for [ & str ] {
2533+ fn spec_extend_into ( self , target : & mut String ) {
2534+ target. push_str_slice ( & self ) ;
2535+ }
2536+ }
2537+
2538+ #[ cfg( not( no_global_oom_handling) ) ]
2539+ impl < const N : usize > SpecExtendStr for [ & str ; N ] {
2540+ fn spec_extend_into ( self , target : & mut String ) {
2541+ target. push_str_slice ( & self [ ..] ) ;
2542+ }
2543+ }
2544+
25012545#[ cfg( not( no_global_oom_handling) ) ]
25022546#[ stable( feature = "box_str2" , since = "1.45.0" ) ]
25032547impl < A : Allocator > Extend < Box < str , A > > for String {
0 commit comments