Add fast path for ascii to ascii in str::replace · qinheping/verify-rust-std@27136c4 (original) (raw)
`@@ -19,7 +19,7 @@ pub use core::str::SplitInclusive;
`
19
19
`pub use core::str::SplitWhitespace;
`
20
20
`#[stable(feature = "rust1", since = "1.0.0")]
`
21
21
`pub use core::str::pattern;
`
22
``
`-
use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher};
`
``
22
`+
use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher, Utf8Pattern};
`
23
23
`#[stable(feature = "rust1", since = "1.0.0")]
`
24
24
`pub use core::str::{Bytes, CharIndices, Chars, from_utf8, from_utf8_mut};
`
25
25
`#[stable(feature = "str_escape", since = "1.34.0")]
`
`@@ -268,6 +268,18 @@ impl str {
`
268
268
`#[stable(feature = "rust1", since = "1.0.0")]
`
269
269
`#[inline]
`
270
270
`pub fn replace<P: Pattern>(&self, from: P, to: &str) -> String {
`
``
271
`+
// Fast path for ASCII to ASCII case.
`
``
272
+
``
273
`+
if let Some(from_byte) = match from.as_utf8_pattern() {
`
``
274
`+
Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte),
`
``
275
`+
Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()),
`
``
276
`+
_ => None,
`
``
277
`+
} {
`
``
278
`+
if let [to_byte] = to.as_bytes() {
`
``
279
`+
return unsafe { replace_ascii(self.as_bytes(), from_byte, *to_byte) };
`
``
280
`+
}
`
``
281
`+
}
`
``
282
+
271
283
`let mut result = String::new();
`
272
284
`let mut last_end = 0;
`
273
285
`for (start, part) in self.match_indices(from) {
`
`@@ -661,3 +673,14 @@ fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec {
`
661
673
``
662
674
` out
`
663
675
`}
`
``
676
`+
#[inline]
`
``
677
`+
#[cfg(not(test))]
`
``
678
`+
#[cfg(not(no_global_oom_handling))]
`
``
679
`+
#[allow(dead_code)]
`
``
680
`+
/// Faster implementation of string replacement for ASCII to ASCII cases.
`
``
681
`+
/// Should produce fast vectorized code.
`
``
682
`+
unsafe fn replace_ascii(utf8_bytes: &[u8], from: u8, to: u8) -> String {
`
``
683
`+
let result: Vec = utf8_bytes.iter().map(|b| if *b == from { to } else { *b }).collect();
`
``
684
`+
// SAFETY: We replaced ascii with ascii on valid utf8 strings.
`
``
685
`+
unsafe { String::from_utf8_unchecked(result) }
`
``
686
`+
}
`