Skip to content

Commit 4a86c79

Browse files
committed
Auto merge of rust-lang#96605 - Urgau:string-retain-codegen, r=thomcc
Improve codegen of String::retain method This pull-request improve the codegen of the `String::retain` method. Using `unwrap_unchecked` helps the optimizer to not generate a panicking path that will never be taken for valid UTF-8 like string. Using `encode_utf8` saves us from an expensive call to `memcpy`, as the optimizer is unable to realize that `ch_len <= 4` and so can generate much better assembly code. https://rust.godbolt.org/z/z73ohenfc
2 parents e57884b + a98abe8 commit 4a86c79

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

library/alloc/src/string.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -1469,19 +1469,28 @@ impl String {
14691469
let mut guard = SetLenOnDrop { s: self, idx: 0, del_bytes: 0 };
14701470

14711471
while guard.idx < len {
1472-
let ch = unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap() };
1472+
let ch =
1473+
// SAFETY: `guard.idx` is positive-or-zero and less that len so the `get_unchecked`
1474+
// is in bound. `self` is valid UTF-8 like string and the returned slice starts at
1475+
// a unicode code point so the `Chars` always return one character.
1476+
unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap_unchecked() };
14731477
let ch_len = ch.len_utf8();
14741478

14751479
if !f(ch) {
14761480
guard.del_bytes += ch_len;
14771481
} else if guard.del_bytes > 0 {
1478-
unsafe {
1479-
ptr::copy(
1480-
guard.s.vec.as_ptr().add(guard.idx),
1481-
guard.s.vec.as_mut_ptr().add(guard.idx - guard.del_bytes),
1482-
ch_len,
1483-
);
1484-
}
1482+
// SAFETY: `guard.idx` is in bound and `guard.del_bytes` represent the number of
1483+
// bytes that are erased from the string so the resulting `guard.idx -
1484+
// guard.del_bytes` always represent a valid unicode code point.
1485+
//
1486+
// `guard.del_bytes` >= `ch.len_utf8()`, so taking a slice with `ch.len_utf8()` len
1487+
// is safe.
1488+
ch.encode_utf8(unsafe {
1489+
crate::slice::from_raw_parts_mut(
1490+
guard.s.as_mut_ptr().add(guard.idx - guard.del_bytes),
1491+
ch.len_utf8(),
1492+
)
1493+
});
14851494
}
14861495

14871496
// Point idx to the next char

0 commit comments

Comments
 (0)