From 18ae175d60039dfe2d2454e8e8099d3b08039862 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 23 Oct 2019 21:00:04 +0200 Subject: [PATCH] Prevent unnecessary allocation in PathBuf::set_extension. It was allocating a new OsString that was immediately dropped after using it with set_file_name. Now it directly changes the extension in the original buffer, without touching the rest of the file name or allocating a temporary string. --- src/libstd/path.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ca81044ee85..6d6bc760649 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1363,20 +1363,24 @@ impl PathBuf { } fn _set_extension(&mut self, extension: &OsStr) -> bool { - if self.file_name().is_none() { - return false; - } - - let mut stem = match self.file_stem() { - Some(stem) => stem.to_os_string(), - None => OsString::new(), + let file_stem = match self.file_stem() { + None => return false, + Some(f) => os_str_as_u8_slice(f), }; - if !os_str_as_u8_slice(extension).is_empty() { - stem.push("."); - stem.push(extension); + // truncate until right after the file stem + let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize; + let start = os_str_as_u8_slice(&self.inner).as_ptr() as usize; + let v = self.as_mut_vec(); + v.truncate(end_file_stem.wrapping_sub(start)); + + // add the new extension, if any + let new = os_str_as_u8_slice(extension); + if !new.is_empty() { + v.reserve_exact(new.len() + 1); + v.push(b'.'); + v.extend_from_slice(new); } - self.set_file_name(&stem); true }