diff options
Diffstat (limited to 'library/alloc/src/string.rs')
| -rw-r--r-- | library/alloc/src/string.rs | 85 |
1 files changed, 57 insertions, 28 deletions
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9236f5cb8d1..9a161d057db 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1043,7 +1043,7 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_bytes(self) -> Vec<u8> { self.vec @@ -1062,7 +1062,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[rustc_diagnostic_item = "string_as_str"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_str(&self) -> &str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1085,7 +1085,7 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[rustc_diagnostic_item = "string_as_mut_str"] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_mut_str(&mut self) -> &mut str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1134,7 +1134,7 @@ impl String { /// assert_eq!(string, "abcdecdeabecde"); /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "string_extend_from_within", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "string_extend_from_within", since = "1.87.0")] pub fn extend_from_within<R>(&mut self, src: R) where R: RangeBounds<usize>, @@ -1159,7 +1159,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1401,11 +1401,14 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, ch: char) { - match ch.len_utf8() { - 1 => self.vec.push(ch as u8), - _ => { - self.vec.extend_from_slice(ch.encode_utf8(&mut [0; char::MAX_LEN_UTF8]).as_bytes()) - } + let len = self.len(); + let ch_len = ch.len_utf8(); + self.reserve(ch_len); + + // SAFETY: Just reserved capacity for at least the length needed to encode `ch`. + unsafe { + core::char::encode_utf8_raw_unchecked(ch as u32, self.vec.as_mut_ptr().add(self.len())); + self.vec.set_len(len + ch_len); } } @@ -1425,7 +1428,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_bytes(&self) -> &[u8] { self.vec.as_slice() } @@ -1702,24 +1705,31 @@ impl String { #[rustc_confusables("set")] pub fn insert(&mut self, idx: usize, ch: char) { assert!(self.is_char_boundary(idx)); - let mut bits = [0; char::MAX_LEN_UTF8]; - let bits = ch.encode_utf8(&mut bits).as_bytes(); + let len = self.len(); + let ch_len = ch.len_utf8(); + self.reserve(ch_len); + + // SAFETY: Move the bytes starting from `idx` to their new location `ch_len` + // bytes ahead. This is safe because sufficient capacity was reserved, and `idx` + // is a char boundary. unsafe { - self.insert_bytes(idx, bits); + ptr::copy( + self.vec.as_ptr().add(idx), + self.vec.as_mut_ptr().add(idx + ch_len), + len - idx, + ); } - } - #[cfg(not(no_global_oom_handling))] - unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { - let len = self.len(); - let amt = bytes.len(); - self.vec.reserve(amt); + // SAFETY: Encode the character into the vacated region if `idx != len`, + // or into the uninitialized spare capacity otherwise. + unsafe { + core::char::encode_utf8_raw_unchecked(ch as u32, self.vec.as_mut_ptr().add(idx)); + } + // SAFETY: Update the length to include the newly added bytes. unsafe { - ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); - ptr::copy_nonoverlapping(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); - self.vec.set_len(len + amt); + self.vec.set_len(len + ch_len); } } @@ -1749,8 +1759,27 @@ impl String { pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); + let len = self.len(); + let amt = string.len(); + self.reserve(amt); + + // SAFETY: Move the bytes starting from `idx` to their new location `amt` bytes + // ahead. This is safe because sufficient capacity was just reserved, and `idx` + // is a char boundary. + unsafe { + ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); + } + + // SAFETY: Copy the new string slice into the vacated region if `idx != len`, + // or into the uninitialized spare capacity otherwise. The borrow checker + // ensures that the source and destination do not overlap. + unsafe { + ptr::copy_nonoverlapping(string.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + } + + // SAFETY: Update the length to include the newly added bytes. unsafe { - self.insert_bytes(idx, string.as_bytes()); + self.vec.set_len(len + amt); } } @@ -1779,7 +1808,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> { &mut self.vec } @@ -1801,7 +1830,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { self.vec.len() @@ -1821,7 +1850,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -3140,7 +3169,7 @@ impl From<String> for Vec<u8> { } } -#[stable(feature = "try_from_vec_u8_for_string", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "try_from_vec_u8_for_string", since = "1.87.0")] impl TryFrom<Vec<u8>> for String { type Error = FromUtf8Error; /// Converts the given [`Vec<u8>`] into a [`String`] if it contains valid UTF-8 data. |
