diff options
| author | bors <bors@rust-lang.org> | 2022-05-21 01:56:51 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-05-21 01:56:51 +0000 |
| commit | 4a86c7907b1e34d14d742fa4c4202626bb77eddc (patch) | |
| tree | ca6b724e0a8e3855c2168c58b4ad9796d7d59951 | |
| parent | e57884b6e96bede12447e21edcdc92fcac59ee46 (diff) | |
| parent | a98abe83eb42b2f537e8a2d7706ba08d9e296f31 (diff) | |
| download | rust-4a86c7907b1e34d14d742fa4c4202626bb77eddc.tar.gz rust-4a86c7907b1e34d14d742fa4c4202626bb77eddc.zip | |
Auto merge of #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
| -rw-r--r-- | library/alloc/src/string.rs | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 2272c5b7330..668af60611b 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1469,19 +1469,28 @@ impl String { let mut guard = SetLenOnDrop { s: self, idx: 0, del_bytes: 0 }; while guard.idx < len { - let ch = unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap() }; + let ch = + // SAFETY: `guard.idx` is positive-or-zero and less that len so the `get_unchecked` + // is in bound. `self` is valid UTF-8 like string and the returned slice starts at + // a unicode code point so the `Chars` always return one character. + unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap_unchecked() }; let ch_len = ch.len_utf8(); if !f(ch) { guard.del_bytes += ch_len; } else if guard.del_bytes > 0 { - unsafe { - ptr::copy( - guard.s.vec.as_ptr().add(guard.idx), - guard.s.vec.as_mut_ptr().add(guard.idx - guard.del_bytes), - ch_len, - ); - } + // SAFETY: `guard.idx` is in bound and `guard.del_bytes` represent the number of + // bytes that are erased from the string so the resulting `guard.idx - + // guard.del_bytes` always represent a valid unicode code point. + // + // `guard.del_bytes` >= `ch.len_utf8()`, so taking a slice with `ch.len_utf8()` len + // is safe. + ch.encode_utf8(unsafe { + crate::slice::from_raw_parts_mut( + guard.s.as_mut_ptr().add(guard.idx - guard.del_bytes), + ch.len_utf8(), + ) + }); } // Point idx to the next char |
