about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-21 01:56:51 +0000
committerbors <bors@rust-lang.org>2022-05-21 01:56:51 +0000
commit4a86c7907b1e34d14d742fa4c4202626bb77eddc (patch)
treeca6b724e0a8e3855c2168c58b4ad9796d7d59951
parente57884b6e96bede12447e21edcdc92fcac59ee46 (diff)
parenta98abe83eb42b2f537e8a2d7706ba08d9e296f31 (diff)
downloadrust-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.rs25
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