@@ -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,23 @@ impl String {
10971099 self . vec . extend_from_slice ( string. as_bytes ( ) )
10981100 }
10991101
1102+ #[ cfg( not( no_global_oom_handling) ) ]
1103+ #[ inline]
1104+ fn push_str_slice ( & mut self , slice : & [ & str ] ) {
1105+ // use saturating arithmetic to ensure that in the case of an overflow, reserve() throws OOM
1106+ let additional: Saturating < usize > = slice. iter ( ) . map ( |x| Saturating ( x. len ( ) ) ) . sum ( ) ;
1107+ self . reserve ( additional. 0 ) ;
1108+ let ( ptr, len, cap) = core:: mem:: take ( self ) . into_raw_parts ( ) ;
1109+ unsafe {
1110+ let mut dst = ptr. add ( len) ;
1111+ for new in slice {
1112+ core:: ptr:: copy_nonoverlapping ( new. as_ptr ( ) , dst, new. len ( ) ) ;
1113+ dst = dst. add ( new. len ( ) ) ;
1114+ }
1115+ * self = String :: from_raw_parts ( ptr, len + additional. 0 , cap) ;
1116+ }
1117+ }
1118+
11001119 /// Copies elements from `src` range to the end of the string.
11011120 ///
11021121 /// # Panics
@@ -2489,7 +2508,7 @@ impl<'a> Extend<&'a char> for String {
24892508#[ stable( feature = "rust1" , since = "1.0.0" ) ]
24902509impl < ' a > Extend < & ' a str > for String {
24912510 fn extend < I : IntoIterator < Item = & ' a str > > ( & mut self , iter : I ) {
2492- iter . into_iter ( ) . for_each ( move |s| self . push_str ( s ) ) ;
2511+ < I as SpecExtendStr > :: spec_extend_into ( iter , self )
24932512 }
24942513
24952514 #[ inline]
@@ -2498,6 +2517,32 @@ impl<'a> Extend<&'a str> for String {
24982517 }
24992518}
25002519
2520+ #[ cfg( not( no_global_oom_handling) ) ]
2521+ trait SpecExtendStr {
2522+ fn spec_extend_into ( self , s : & mut String ) ;
2523+ }
2524+
2525+ #[ cfg( not( no_global_oom_handling) ) ]
2526+ impl < ' a , T : IntoIterator < Item = & ' a str > > SpecExtendStr for T {
2527+ default fn spec_extend_into ( self , target : & mut String ) {
2528+ self . into_iter ( ) . for_each ( move |s| target. push_str ( s) ) ;
2529+ }
2530+ }
2531+
2532+ #[ cfg( not( no_global_oom_handling) ) ]
2533+ impl SpecExtendStr for [ & str ] {
2534+ fn spec_extend_into ( self , target : & mut String ) {
2535+ target. push_str_slice ( & self ) ;
2536+ }
2537+ }
2538+
2539+ #[ cfg( not( no_global_oom_handling) ) ]
2540+ impl < const N : usize > SpecExtendStr for [ & str ; N ] {
2541+ fn spec_extend_into ( self , target : & mut String ) {
2542+ target. push_str_slice ( & self [ ..] ) ;
2543+ }
2544+ }
2545+
25012546#[ cfg( not( no_global_oom_handling) ) ]
25022547#[ stable( feature = "box_str2" , since = "1.45.0" ) ]
25032548impl < A : Allocator > Extend < Box < str , A > > for String {
0 commit comments