From 347da74edabf329ce84ec81cf22bd65ef944199b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 26 Nov 2020 23:08:02 +0100 Subject: Avoid allocation in ast::String::value if the string needs no unescaping --- crates/syntax/src/ast/token_ext.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index ac0326420..b985861f2 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -130,19 +130,28 @@ impl ast::String { let text = self.text().as_str(); let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; - let mut buf = String::with_capacity(text.len()); + let mut buf = String::new(); + let mut text_iter = text.chars(); let mut has_error = false; - unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char { - Ok(c) => buf.push(c), - Err(_) => has_error = true, + unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( + unescaped_char, + buf.capacity() == 0, + ) { + (Ok(c), false) => buf.push(c), + (Ok(c), true) if Some(c) == text_iter.next() => (), + (Ok(c), true) => { + buf.reserve_exact(text.len()); + buf.push_str(&text[..char_range.start]); + buf.push(c); + } + (Err(_), _) => has_error = true, }); - if has_error { - return None; + match (has_error, buf.capacity() == 0) { + (true, _) => None, + (false, true) => Some(Cow::Borrowed(text)), + (false, false) => Some(Cow::Owned(buf)), } - // FIXME: don't actually allocate for borrowed case - let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) }; - Some(res) } pub fn quote_offsets(&self) -> Option { -- cgit v1.2.3