Skip to content

Commit ca39ddb

Browse files
authored
Rollup merge of #160536 - fereidani:utf16_units, r=clarfonthey
Inline `String::into_raw_parts` and reuse `from_utf16` optimization 1. I noticed that comment `// This isn't done via collect::<Result<_, _>>() for performance reasons.` explicitly states that this approach is wrong, but `from_utf16le` and `from_utf16be` are not using the same optimization. 2. I believe `into_raw_parts` is missing the `#[inline]` as any other similar functions in the standard library are marked either with `inline` or `inline(always)`. This is also related to #48994; whenever that fix lands, optimizing `from_utf16_units` will results in these 3 functions getting optimized.
2 parents 7f9b824 + f741ac8 commit ca39ddb

1 file changed

Lines changed: 23 additions & 10 deletions

File tree

‎library/alloc/src/string.rs‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -721,10 +721,22 @@ impl String {
721721
#[cfg(not(no_global_oom_handling))]
722722
#[stable(feature = "rust1", since = "1.0.0")]
723723
pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
724-
// This isn't done via collect::<Result<_, _>>() for performance reasons.
725-
// FIXME: the function can be simplified again when #48994 is closed.
726-
let mut ret = String::with_capacity(v.len());
727-
for c in char::decode_utf16(v.iter().cloned()) {
724+
Self::from_utf16_units(v.iter().cloned(), v.len())
725+
}
726+
727+
/// Decodes an iterator of UTF-16 code units into a `String`, returning
728+
/// [`Err`] on the first lone surrogate. `capacity` should be the number of
729+
/// code units, which is used to preallocate the output buffer.
730+
// This isn't done via collect::<Result<_, _>>() for performance reasons.
731+
// FIXME: the function can be simplified again when #48994 is closed.
732+
#[cfg(not(no_global_oom_handling))]
733+
#[inline]
734+
fn from_utf16_units(
735+
units: impl Iterator<Item = u16>,
736+
capacity: usize,
737+
) -> Result<String, FromUtf16Error> {
738+
let mut ret = String::with_capacity(capacity);
739+
for c in char::decode_utf16(units) {
728740
let Ok(c) = c else {
729741
return Err(FromUtf16Error { kind: FromUtf16ErrorKind::LoneSurrogate });
730742
};
@@ -792,9 +804,9 @@ impl String {
792804
};
793805
match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) {
794806
(true, ([], v, [])) => Self::from_utf16(v),
795-
_ => char::decode_utf16(chunks.iter().copied().map(u16::from_le_bytes))
796-
.collect::<Result<_, _>>()
797-
.map_err(|_| FromUtf16Error { kind: FromUtf16ErrorKind::LoneSurrogate }),
807+
_ => {
808+
Self::from_utf16_units(chunks.iter().copied().map(u16::from_le_bytes), chunks.len())
809+
}
798810
}
799811
}
800812

@@ -865,9 +877,9 @@ impl String {
865877
};
866878
match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) {
867879
(true, ([], v, [])) => Self::from_utf16(v),
868-
_ => char::decode_utf16(chunks.iter().copied().map(u16::from_be_bytes))
869-
.collect::<Result<_, _>>()
870-
.map_err(|_| FromUtf16Error { kind: FromUtf16ErrorKind::LoneSurrogate }),
880+
_ => {
881+
Self::from_utf16_units(chunks.iter().copied().map(u16::from_be_bytes), chunks.len())
882+
}
871883
}
872884
}
873885

@@ -938,6 +950,7 @@ impl String {
938950
/// ```
939951
#[must_use = "losing the pointer will leak memory"]
940952
#[stable(feature = "vec_into_raw_parts", since = "1.93.0")]
953+
#[inline]
941954
pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
942955
self.vec.into_raw_parts()
943956
}

0 commit comments

Comments
 (0)