From dcb12abbae80e062e393fe39cfcd0b16faef15f8 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Wed, 7 Oct 2020 13:32:12 -0500 Subject: [PATCH] Don't double loop over chunks --- vm/src/stdlib/json/machinery.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/vm/src/stdlib/json/machinery.rs b/vm/src/stdlib/json/machinery.rs index c5b8495d5..0e041f55c 100644 --- a/vm/src/stdlib/json/machinery.rs +++ b/vm/src/stdlib/json/machinery.rs @@ -123,16 +123,24 @@ impl StrOrChar<'_> { } } } -pub fn scanstring(s: &str, end: usize, strict: bool) -> Result<(String, usize), DecodeError> { - let mut chunks: Vec = Vec::new(); +pub fn scanstring<'a>( + s: &'a str, + end: usize, + strict: bool, +) -> Result<(String, usize), DecodeError> { + let mut chunks: Vec> = Vec::new(); + let mut output_len = 0usize; + let mut push_chunk = |chunk: StrOrChar<'a>| { + output_len += chunk.len(); + chunks.push(chunk); + }; let mut chunk_start = end; let mut chars = s.char_indices().enumerate().skip(end).peekable(); while let Some((char_i, (i, c))) = chars.next() { match c { '"' => { - chunks.push(StrOrChar::Str(&s[chunk_start..i])); - let len = chunks.iter().map(|x| x.len()).sum(); - let mut out = String::with_capacity(len); + push_chunk(StrOrChar::Str(&s[chunk_start..i])); + let mut out = String::with_capacity(output_len); for x in chunks { match x { StrOrChar::Str(s) => out.push_str(s), @@ -158,7 +166,7 @@ pub fn scanstring(s: &str, end: usize, strict: bool) -> Result<(String, usize), 't' => "\t", 'u' => { let surrogate_err = || DecodeError::new("unpaired surrogate", char_i); - chunks.push(StrOrChar::Str(&s[chunk_start..i])); + push_chunk(StrOrChar::Str(&s[chunk_start..i])); let mut uni = decode_unicode(&mut chars, char_i)?; chunk_start = char_i + 6; if (0xd800..=0xdbff).contains(&uni) { @@ -184,7 +192,7 @@ pub fn scanstring(s: &str, end: usize, strict: bool) -> Result<(String, usize), } } } - chunks.push(StrOrChar::Char( + push_chunk(StrOrChar::Char( std::char::from_u32(uni).ok_or_else(surrogate_err)?, )); continue; @@ -196,9 +204,9 @@ pub fn scanstring(s: &str, end: usize, strict: bool) -> Result<(String, usize), )) } }; - chunks.push(StrOrChar::Str(&s[chunk_start..i])); + push_chunk(StrOrChar::Str(&s[chunk_start..i])); chunk_start = i + 2; - chunks.push(StrOrChar::Str(esc)); + push_chunk(StrOrChar::Str(esc)); } '\x00'..='\x1f' if strict => { return Err(DecodeError::new(