@@ -50,9 +50,9 @@ use core::iter::from_fn;
5050use core:: num:: Saturating ;
5151#[ cfg( not( no_global_oom_handling) ) ]
5252use core:: ops:: Add ;
53- #[ cfg( not( no_global_oom_handling) ) ]
54- use core:: ops:: AddAssign ;
5553use core:: ops:: { self , Range , RangeBounds } ;
54+ #[ cfg( not( no_global_oom_handling) ) ]
55+ use core:: ops:: { AddAssign , ControlFlow } ;
5656use core:: str:: pattern:: { Pattern , Utf8Pattern } ;
5757use core:: { fmt, hash, ptr, slice} ;
5858
@@ -61,7 +61,7 @@ use crate::alloc::Allocator;
6161#[ cfg( not( no_global_oom_handling) ) ]
6262use crate :: borrow:: { Cow , ToOwned } ;
6363use crate :: boxed:: Box ;
64- use crate :: collections:: { TryReserveError } ;
64+ use crate :: collections:: TryReserveError ;
6565#[ cfg( not( no_global_oom_handling) ) ]
6666use crate :: collections:: VecDeque ;
6767use crate :: str:: { self , CharIndices , Chars , Utf8Error , from_utf8_unchecked_mut} ;
@@ -3610,6 +3610,25 @@ impl From<char> for String {
36103610// In place case changes
36113611
36123612impl String {
3613+ #[ cfg( not( no_global_oom_handling) ) ]
3614+ fn case_change_while_ascii < const MAKE_UPPER : bool > ( & mut self ) -> ControlFlow < usize > {
3615+ // SAFETY the as_bytes_mut is unsafe but we will only do ascii case change in place with it
3616+ unsafe {
3617+ self . as_bytes_mut ( ) . into_iter ( ) . enumerate ( ) . try_for_each ( |( i, b) | {
3618+ if b. is_ascii ( ) {
3619+ if MAKE_UPPER {
3620+ b. make_ascii_uppercase ( ) ;
3621+ } else {
3622+ b. make_ascii_lowercase ( ) ;
3623+ }
3624+ ControlFlow :: Continue ( ( ) )
3625+ } else {
3626+ ControlFlow :: Break ( i)
3627+ }
3628+ } )
3629+ }
3630+ }
3631+
36133632 /// Converts this string to its uppercase equivalent in-place.
36143633 ///
36153634 /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property
@@ -3656,7 +3675,10 @@ impl String {
36563675 #[ cfg( not( no_global_oom_handling) ) ]
36573676 #[ unstable( feature = "string_make_uplowercase" , issue = "135885" ) ]
36583677 pub fn make_uppercase ( & mut self ) {
3659- let mut wc = WriteChars :: new ( self ) ;
3678+ let ControlFlow :: Break ( non_utf8_offset) = self . case_change_while_ascii :: < true > ( ) else {
3679+ return ;
3680+ } ;
3681+ let mut wc = WriteChars :: new ( self , non_utf8_offset) ;
36603682 while let Some ( l_c) = wc. pop ( ) {
36613683 l_c. to_uppercase ( ) . for_each ( |u_c| wc. write ( u_c) ) ;
36623684 }
@@ -3710,11 +3732,19 @@ impl String {
37103732 #[ cfg( not( no_global_oom_handling) ) ]
37113733 #[ unstable( feature = "string_make_uplowercase" , issue = "135885" ) ]
37123734 pub fn make_lowercase ( & mut self ) {
3735+ fn update_word_final ( word_final_so_far : bool , u_c : char ) -> bool {
3736+ u_c. is_cased ( ) || ( word_final_so_far && u_c. is_case_ignorable ( ) )
3737+ }
3738+
3739+ let ControlFlow :: Break ( non_utf8_offset) = self . case_change_while_ascii :: < false > ( ) else {
3740+ return ;
3741+ } ;
37133742 // We will only update the streaming word_final detection if the str contains sigma
37143743 // because it requires table lookups that we consider expensive.
3715- let has_sigma = self . contains ( 'Σ' ) ;
3716- let mut word_final_so_far = false ;
3717- let mut wc = WriteChars :: new ( self ) ;
3744+ let has_sigma = self [ non_utf8_offset..] . contains ( 'Σ' ) ;
3745+ let mut word_final_so_far =
3746+ has_sigma && self [ ..non_utf8_offset] . chars ( ) . fold ( false , update_word_final) ;
3747+ let mut wc = WriteChars :: new ( self , non_utf8_offset) ;
37183748 while let Some ( u_c) = wc. pop ( ) {
37193749 if u_c == 'Σ' {
37203750 if word_final_so_far && !crate :: str:: case_ignorable_then_cased ( wc. rest ( ) . chars ( ) ) {
@@ -3727,8 +3757,7 @@ impl String {
37273757 u_c. to_lowercase ( ) . for_each ( |l_c| wc. write ( l_c) ) ;
37283758 }
37293759 if has_sigma {
3730- word_final_so_far =
3731- u_c. is_cased ( ) || ( word_final_so_far && u_c. is_case_ignorable ( ) ) ;
3760+ word_final_so_far = update_word_final ( word_final_so_far, u_c) ;
37323761 }
37333762 }
37343763 // SAFETY: At this point, none of the methods of wc panicked
@@ -3738,6 +3767,8 @@ impl String {
37383767 }
37393768}
37403769
3770+ #[ cfg( not( no_global_oom_handling) ) ]
3771+
37413772/// A helper for in place modification of strings, where we gradually "pop" characters,
37423773/// hereby making room to write back to the string buffer
37433774#[ unstable( issue = "none" , feature = "std_internals" ) ]
@@ -3759,9 +3790,9 @@ struct WriteChars<'a> {
37593790
37603791#[ unstable( issue = "none" , feature = "std_internals" ) ]
37613792impl < ' a > WriteChars < ' a > {
3762- fn new ( s : & ' a mut String ) -> Self {
3793+ fn new ( s : & ' a mut String , offset : usize ) -> Self {
37633794 let v = core:: mem:: take ( s) . into_bytes ( ) ;
3764- WriteChars { s, v, write_offset : 0 , read_offset : 0 , buffer : VecDeque :: new ( ) }
3795+ WriteChars { s, v, write_offset : offset , read_offset : offset , buffer : VecDeque :: new ( ) }
37653796 }
37663797
37673798 fn rest ( & self ) -> & str {
0 commit comments