4242
4343#![ stable( feature = "rust1" , since = "1.0.0" ) ]
4444
45+ #[ cfg( not( no_global_oom_handling) ) ]
46+ use core:: array;
4547use core:: error:: Error ;
4648use core:: iter:: FusedIterator ;
4749#[ cfg( not( no_global_oom_handling) ) ]
@@ -2200,6 +2202,36 @@ impl String {
22002202 let slice = self . vec . leak ( ) ;
22012203 unsafe { from_utf8_unchecked_mut ( slice) }
22022204 }
2205+
2206+ /// SAFETY: When calling `<S as AsRef<str>>::as_ref()` multiple times, the same value must be returned.
2207+ #[ cfg( not( no_global_oom_handling) ) ]
2208+ unsafe fn extend_many < S : AsRef < str > > ( & mut self , vals : & [ S ] ) {
2209+ let additional = vals. iter ( ) . fold ( 0usize , |a, s| a. saturating_add ( s. as_ref ( ) . len ( ) ) ) ;
2210+ self . reserve ( additional) ;
2211+
2212+ let mut spare = self . vec . spare_capacity_mut ( ) . as_mut_ptr ( ) . cast_init ( ) ;
2213+ for val in vals {
2214+ let val = val. as_ref ( ) ;
2215+ // SAFETY:
2216+ // - `val` is a valid &str, so `val.as_ptr()` is valid
2217+ // for `val.len()` bytes and properly initialized.
2218+ // - `spare` points to valid spare capacity in the Vec
2219+ // with enough space for `val.len()` bytes.
2220+ // This is guaranteed because the caller ensures
2221+ // that multiple calls to `<S as AsRef<str>>::as_ref()`
2222+ // return the same value, and the saturating addition
2223+ // stops undercounting by overflow.
2224+ // - Both pointers are byte-aligned and the regions cannot overlap.
2225+ unsafe {
2226+ ptr:: copy_nonoverlapping ( val. as_ptr ( ) , spare, val. len ( ) ) ;
2227+ spare = spare. add ( val. len ( ) ) ;
2228+ }
2229+ }
2230+
2231+ let new_len = self . vec . len ( ) + additional;
2232+ // SAFETY: the elements have just been initialized
2233+ unsafe { self . vec . set_len ( new_len) }
2234+ }
22032235}
22042236
22052237impl FromUtf8Error {
@@ -2499,7 +2531,8 @@ impl<'a> Extend<&'a char> for String {
24992531#[ stable( feature = "rust1" , since = "1.0.0" ) ]
25002532impl < ' a > Extend < & ' a str > for String {
25012533 fn extend < I : IntoIterator < Item = & ' a str > > ( & mut self , iter : I ) {
2502- iter. into_iter ( ) . for_each ( move |s| self . push_str ( s) ) ;
2534+ // SAFETY: `<&str as AsRef<str>>::as_ref()` returns the same value when called multiple times
2535+ unsafe { self . extend_many_chunked ( iter. into_iter ( ) ) }
25032536 }
25042537
25052538 #[ inline]
@@ -2512,15 +2545,17 @@ impl<'a> Extend<&'a str> for String {
25122545#[ stable( feature = "box_str2" , since = "1.45.0" ) ]
25132546impl < A : Allocator > Extend < Box < str , A > > for String {
25142547 fn extend < I : IntoIterator < Item = Box < str , A > > > ( & mut self , iter : I ) {
2515- iter. into_iter ( ) . for_each ( move |s| self . push_str ( & s) ) ;
2548+ // SAFETY: `<Box<str, A> as AsRef<str>>::as_ref()` returns the same value when called multiple times
2549+ unsafe { self . extend_many_chunked ( iter. into_iter ( ) ) }
25162550 }
25172551}
25182552
25192553#[ cfg( not( no_global_oom_handling) ) ]
25202554#[ stable( feature = "extend_string" , since = "1.4.0" ) ]
25212555impl Extend < String > for String {
25222556 fn extend < I : IntoIterator < Item = String > > ( & mut self , iter : I ) {
2523- iter. into_iter ( ) . for_each ( move |s| self . push_str ( & s) ) ;
2557+ // SAFETY: `<String as AsRef<str>>::as_ref()` returns the same value when called multiple times
2558+ unsafe { self . extend_many_chunked ( iter. into_iter ( ) ) }
25242559 }
25252560
25262561 #[ inline]
@@ -2533,7 +2568,8 @@ impl Extend<String> for String {
25332568#[ stable( feature = "herd_cows" , since = "1.19.0" ) ]
25342569impl < ' a > Extend < Cow < ' a , str > > for String {
25352570 fn extend < I : IntoIterator < Item = Cow < ' a , str > > > ( & mut self , iter : I ) {
2536- iter. into_iter ( ) . for_each ( move |s| self . push_str ( & s) ) ;
2571+ // SAFETY: `<Cow<'a, str> as AsRef<str>>::as_ref()` returns the same value when called multiple times
2572+ unsafe { self . extend_many_chunked ( iter. into_iter ( ) ) }
25372573 }
25382574
25392575 #[ inline]
@@ -2570,6 +2606,57 @@ impl<'a> Extend<&'a core::ascii::Char> for String {
25702606 }
25712607}
25722608
2609+ #[ cfg( not( no_global_oom_handling) ) ]
2610+ trait ExtendManySpec < S , I > {
2611+ /// SAFETY: When calling `<S as AsRef<str>>::as_ref()` multiple times, the same value must be returned.
2612+ unsafe fn extend_many_chunked ( & mut self , iter : I ) ;
2613+ }
2614+
2615+ #[ cfg( not( no_global_oom_handling) ) ]
2616+ impl < S , I > ExtendManySpec < S , I > for String
2617+ where
2618+ S : AsRef < str > ,
2619+ I : Iterator < Item = S > ,
2620+ {
2621+ default unsafe fn extend_many_chunked ( & mut self , mut iter : I ) {
2622+ let mut repeat = true ;
2623+ while repeat {
2624+ let chunk = match iter. next_chunk :: < 8 > ( ) {
2625+ Ok ( chunk) => chunk. into_iter ( ) ,
2626+ Err ( partial_chunk) => {
2627+ repeat = false ;
2628+ partial_chunk
2629+ }
2630+ } ;
2631+
2632+ // SAFETY: the caller ensures that multiple calls to `<S as AsRef<str>>::as_ref()` return the same value.
2633+ unsafe { self . extend_many ( chunk. as_slice ( ) ) }
2634+ }
2635+ }
2636+ }
2637+
2638+ #[ cfg( not( no_global_oom_handling) ) ]
2639+ impl < S , const N : usize > ExtendManySpec < S , array:: IntoIter < S , N > > for String
2640+ where
2641+ S : AsRef < str > ,
2642+ {
2643+ unsafe fn extend_many_chunked ( & mut self , iter : array:: IntoIter < S , N > ) {
2644+ // SAFETY: the caller ensures that multiple calls to `<S as AsRef<str>>::as_ref()` return the same value.
2645+ unsafe { self . extend_many ( iter. as_slice ( ) ) }
2646+ }
2647+ }
2648+
2649+ #[ cfg( not( no_global_oom_handling) ) ]
2650+ impl < S > ExtendManySpec < S , vec:: IntoIter < S > > for String
2651+ where
2652+ S : AsRef < str > ,
2653+ {
2654+ unsafe fn extend_many_chunked ( & mut self , iter : vec:: IntoIter < S > ) {
2655+ // SAFETY: the caller ensures that multiple calls to `<S as AsRef<str>>::as_ref()` return the same value.
2656+ unsafe { self . extend_many ( iter. as_slice ( ) ) }
2657+ }
2658+ }
2659+
25732660/// A convenience impl that delegates to the impl for `&str`.
25742661///
25752662/// # Examples
0 commit comments