From 30c06570f7c0c51945112b1de50abe8460572396 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 22 Aug 2024 17:33:44 +0800 Subject: [PATCH 01/13] perf: remove WithIndices --- src/replace_source.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/replace_source.rs b/src/replace_source.rs index ab140093..d1ced1b5 100644 --- a/src/replace_source.rs +++ b/src/replace_source.rs @@ -12,7 +12,6 @@ use rustc_hash::FxHashMap as HashMap; use crate::{ helpers::{get_map, split_into_lines, GeneratedInfo, StreamChunks}, - with_indices::WithIndices, MapOptions, Mapping, OriginalLocation, Source, SourceMap, }; @@ -312,10 +311,17 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { source_content_lines.borrow().get(source_index as usize) { if let Some(content_line) = content_lines.get(line as usize - 1) { - WithIndices::new(content_line).substring( - column as usize, - column as usize + expected_chunk.len(), - ) == expected_chunk + match content_line + .char_indices() + .nth(column as usize) + .map(|(byte_index, _)| byte_index) + { + Some(byte_index) => { + content_line.get(byte_index..byte_index + expected_chunk.len()) + == Some(expected_chunk) + } + None => false, + } } else { false } @@ -323,6 +329,7 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { false } }; + let result = self.inner.stream_chunks( &MapOptions { columns: options.columns, From 853432f67645e955bd81b9d0e4e9620e30d2fa4e Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 22 Aug 2024 17:36:05 +0800 Subject: [PATCH 02/13] perf: remove Rc --- src/helpers.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 86076667..b9160977 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,7 +3,6 @@ use rustc_hash::FxHashMap as HashMap; use std::{ borrow::{BorrowMut, Cow}, cell::{OnceCell, RefCell}, - rc::Rc, }; use crate::{ @@ -15,7 +14,7 @@ use crate::{ // Adding this type because sourceContentLine not happy type InnerSourceContentLine<'a> = - RefCell>>>>>; + RefCell>>>>; pub fn get_map<'a, S: StreamChunks<'a>>( stream: &'a S, @@ -1046,11 +1045,11 @@ pub fn stream_chunks_of_combined_source_map<'a>( original_source_lines = if let Some(Some(original_source)) = inner_source_contents.get(&inner_source_index) { - Some(Rc::new( + Some( split_into_lines(original_source) .map(WithIndices::new) .collect(), - )) + ) } else { None }; @@ -1148,12 +1147,10 @@ pub fn stream_chunks_of_combined_source_map<'a>( .and_then(|original_source| { original_source.as_ref().map(|s| { let lines = split_into_lines(s); - Rc::new( - lines - .into_iter() - .map(WithIndices::new) - .collect::>(), - ) + lines + .into_iter() + .map(WithIndices::new) + .collect::>() }) }); inner_source_content_lines From 9be10eefda3ab8f2f4fff9288b848886d97470b6 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 22 Aug 2024 17:39:14 +0800 Subject: [PATCH 03/13] perf: remove SourceMapLineChunk --- src/helpers.rs | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b9160977..7f994c25 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,7 +2,7 @@ use arrayvec::ArrayVec; use rustc_hash::FxHashMap as HashMap; use std::{ borrow::{BorrowMut, Cow}, - cell::{OnceCell, RefCell}, + cell::RefCell, }; use crate::{ @@ -265,7 +265,7 @@ fn encode_full_mappings(mappings: &[Mapping]) -> String { let mut initial = true; mappings.iter().fold( - String::with_capacity(mappings.len() * 6), + String::new(), |mut acc, mapping| { if active_mapping && current_line == mapping.generated_line { // A mapping is still active @@ -901,29 +901,7 @@ fn stream_chunks_of_source_map_lines_full<'a>( #[derive(Debug)] struct SourceMapLineData<'a> { pub mappings_data: Vec, - pub chunks: Vec>, -} - -#[derive(Debug)] -struct SourceMapLineChunk<'a> { - content: Cow<'a, str>, - cached: OnceCell>>, -} - -impl<'a> SourceMapLineChunk<'a> { - pub fn new(content: Cow<'a, str>) -> Self { - Self { - content, - cached: OnceCell::new(), - } - } - - pub fn substring(&self, start_index: usize, end_index: usize) -> &str { - let cached = self - .cached - .get_or_init(|| WithIndices::new(self.content.clone())); - cached.substring(start_index, end_index) - } + pub chunks: Vec>>, } type InnerSourceIndexValueMapping<'a> = @@ -1355,7 +1333,7 @@ pub fn stream_chunks_of_combined_source_map<'a>( .unwrap_or(-1), ); // SAFETY: final_source is false - let chunk = SourceMapLineChunk::new(chunk.unwrap()); + let chunk = WithIndices::new(chunk.unwrap()); data.chunks.push(chunk); }, &mut |i, source, source_content| { From 23518c85eaedb2b929706029b954167e0f291634 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 22 Aug 2024 21:06:35 +0800 Subject: [PATCH 04/13] perf --- src/encoder.rs | 232 +++++++++++++++++++++++++++++++++++++++++++++++++ src/helpers.rs | 171 +++--------------------------------- src/lib.rs | 2 + 3 files changed, 244 insertions(+), 161 deletions(-) create mode 100644 src/encoder.rs diff --git a/src/encoder.rs b/src/encoder.rs new file mode 100644 index 00000000..1389b284 --- /dev/null +++ b/src/encoder.rs @@ -0,0 +1,232 @@ +use crate::{vlq::encode, Mapping}; + +pub(crate) trait MappingsEncoder { + fn encode(&mut self, mapping: &Mapping); + fn drain(self: Box) -> String; +} + +pub fn create_encoder(columns: bool) -> Box { + if columns { + Box::new(FullMappingsEncoder::new()) + } else { + Box::new(LinesOnlyMappingsEncoder::new()) + } +} + +struct FullMappingsEncoder { + current_line: u32, + current_column: u32, + current_original_line: u32, + current_original_column: u32, + current_source_index: u32, + current_name_index: u32, + active_mapping: bool, + active_name: bool, + initial: bool, + mappings: String, +} + +impl FullMappingsEncoder { + pub fn new() -> Self { + Self { + current_line: 1, + current_column: 0, + current_original_line: 1, + current_original_column: 0, + current_source_index: 0, + current_name_index: 0, + active_mapping: false, + active_name: false, + initial: true, + mappings: Default::default(), + } + } +} + +impl MappingsEncoder for FullMappingsEncoder { + fn encode(&mut self, mapping: &Mapping) { + if self.active_mapping && self.current_line == mapping.generated_line { + // A mapping is still active + if mapping.original.is_some_and(|original| { + original.source_index == self.current_source_index + && original.original_line == self.current_original_line + && original.original_column == self.current_original_column + && !self.active_name + && original.name_index.is_none() + }) { + // avoid repeating the same original mapping + return; + } + } else { + // No mapping is active + if mapping.original.is_none() { + // avoid writing unnecessary generated mappings + return; + } + } + + if self.current_line < mapping.generated_line { + (0..mapping.generated_line - self.current_line) + .for_each(|_| self.mappings.push(';')); + self.current_line = mapping.generated_line; + self.current_column = 0; + self.initial = false; + } else if self.initial { + self.initial = false; + } else { + self.mappings.push(','); + } + + encode( + &mut self.mappings, + mapping.generated_column, + self.current_column, + ); + self.current_column = mapping.generated_column; + if let Some(original) = &mapping.original { + self.active_mapping = true; + if original.source_index == self.current_source_index { + self.mappings.push('A'); + } else { + encode( + &mut self.mappings, + original.source_index, + self.current_source_index, + ); + self.current_source_index = original.source_index; + } + encode( + &mut self.mappings, + original.original_line, + self.current_original_line, + ); + self.current_original_line = original.original_line; + if original.original_column == self.current_original_column { + self.mappings.push('A'); + } else { + encode( + &mut self.mappings, + original.original_column, + self.current_original_column, + ); + self.current_original_column = original.original_column; + } + if let Some(name_index) = original.name_index { + encode(&mut self.mappings, name_index, self.current_name_index); + self.current_name_index = name_index; + self.active_name = true; + } else { + self.active_name = false; + } + } else { + self.active_mapping = false; + } + } + + fn drain(self: Box) -> String { + self.mappings + } +} + +pub(crate) struct LinesOnlyMappingsEncoder { + last_written_line: u32, + current_line: u32, + current_source_index: u32, + current_original_line: u32, + mappings: String, +} + +impl LinesOnlyMappingsEncoder { + pub fn new() -> Self { + Self { + last_written_line: 0, + current_line: 1, + current_source_index: 0, + current_original_line: 1, + mappings: Default::default(), + } + } +} + +impl MappingsEncoder for LinesOnlyMappingsEncoder { + fn encode(&mut self, mapping: &Mapping) { + if let Some(original) = &mapping.original { + if self.last_written_line == mapping.generated_line { + // avoid writing multiple original mappings per line + return; + } + self.last_written_line = mapping.generated_line; + if mapping.generated_line == self.current_line + 1 { + self.current_line = mapping.generated_line; + if original.source_index == self.current_source_index { + if original.original_line == self.current_original_line + 1 { + self.current_original_line = original.original_line; + self.mappings.push_str(";AACA"); + } else { + self.mappings.push_str(";AA"); + encode( + &mut self.mappings, + original.original_line, + self.current_original_line, + ); + self.current_original_line = original.original_line; + self.mappings.push('A'); + } + } else { + self.mappings.push_str(";A"); + encode( + &mut self.mappings, + original.source_index, + self.current_source_index, + ); + self.current_source_index = original.source_index; + encode( + &mut self.mappings, + original.original_line, + self.current_original_line, + ); + self.current_original_line = original.original_line; + self.mappings.push('A'); + } + } else { + (0..mapping.generated_line - self.current_line) + .for_each(|_| self.mappings.push(';')); + self.current_line = mapping.generated_line; + if original.source_index == self.current_source_index { + if original.original_line == self.current_original_line + 1 { + self.current_original_line = original.original_line; + self.mappings.push_str("AACA"); + } else { + self.mappings.push_str("AA"); + encode( + &mut self.mappings, + original.original_line, + self.current_original_line, + ); + self.current_original_line = original.original_line; + self.mappings.push('A'); + } + } else { + self.mappings.push('A'); + encode( + &mut self.mappings, + original.source_index, + self.current_source_index, + ); + self.current_source_index = original.source_index; + encode( + &mut self.mappings, + original.original_line, + self.current_original_line, + ); + self.current_original_line = original.original_line; + self.mappings.push('A'); + } + } + } + } + + fn drain(self: Box) -> String { + self.mappings + } +} diff --git a/src/helpers.rs b/src/helpers.rs index 7f994c25..a4648c4c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -6,8 +6,9 @@ use std::{ }; use crate::{ + encoder::create_encoder, source::{Mapping, OriginalLocation}, - vlq::{decode, encode}, + vlq::decode, with_indices::WithIndices, MapOptions, SourceMap, }; @@ -20,10 +21,11 @@ pub fn get_map<'a, S: StreamChunks<'a>>( stream: &'a S, options: &'a MapOptions, ) -> Option { - let mut mappings = Vec::new(); + let mut mappings_encoder = create_encoder(options.columns); let mut sources: Vec> = Vec::new(); let mut sources_content: Vec> = Vec::new(); let mut names: Vec> = Vec::new(); + stream.stream_chunks( &MapOptions { columns: options.columns, @@ -31,7 +33,7 @@ pub fn get_map<'a, S: StreamChunks<'a>>( }, // on_chunk &mut |_, mapping| { - mappings.push(mapping); + mappings_encoder.encode(&mapping); }, // on_source &mut |source_index, source, source_content| { @@ -56,7 +58,7 @@ pub fn get_map<'a, S: StreamChunks<'a>>( names[name_index] = name.to_string().into(); }, ); - let mappings = encode_mappings(&mappings, options); + let mappings = mappings_encoder.drain(); (!mappings.is_empty()) .then(|| SourceMap::new(None, mappings, sources, sources_content, names)) } @@ -245,160 +247,6 @@ impl<'a> Iterator for SegmentIter<'a> { } } -pub fn encode_mappings(mappings: &[Mapping], options: &MapOptions) -> String { - if options.columns { - encode_full_mappings(mappings) - } else { - encode_lines_only_mappings(mappings) - } -} - -fn encode_full_mappings(mappings: &[Mapping]) -> String { - let mut current_line = 1; - let mut current_column = 0; - let mut current_original_line = 1; - let mut current_original_column = 0; - let mut current_source_index = 0; - let mut current_name_index = 0; - let mut active_mapping = false; - let mut active_name = false; - let mut initial = true; - - mappings.iter().fold( - String::new(), - |mut acc, mapping| { - if active_mapping && current_line == mapping.generated_line { - // A mapping is still active - if mapping.original.is_some_and(|original| { - original.source_index == current_source_index - && original.original_line == current_original_line - && original.original_column == current_original_column - && !active_name - && original.name_index.is_none() - }) { - // avoid repeating the same original mapping - return acc; - } - } else { - // No mapping is active - if mapping.original.is_none() { - // avoid writing unnecessary generated mappings - return acc; - } - } - - if current_line < mapping.generated_line { - (0..mapping.generated_line - current_line).for_each(|_| acc.push(';')); - current_line = mapping.generated_line; - current_column = 0; - initial = false; - } else if initial { - initial = false; - } else { - acc.push(','); - } - - encode(&mut acc, mapping.generated_column, current_column); - current_column = mapping.generated_column; - if let Some(original) = &mapping.original { - active_mapping = true; - if original.source_index == current_source_index { - acc.push('A'); - } else { - encode(&mut acc, original.source_index, current_source_index); - current_source_index = original.source_index; - } - encode(&mut acc, original.original_line, current_original_line); - current_original_line = original.original_line; - if original.original_column == current_original_column { - acc.push('A'); - } else { - encode(&mut acc, original.original_column, current_original_column); - current_original_column = original.original_column; - } - if let Some(name_index) = original.name_index { - encode(&mut acc, name_index, current_name_index); - current_name_index = name_index; - active_name = true; - } else { - active_name = false; - } - } else { - active_mapping = false; - } - acc - }, - ) -} - -fn encode_lines_only_mappings(mappings: &[Mapping]) -> String { - let mut last_written_line = 0; - let mut current_line = 1; - let mut current_source_index = 0; - let mut current_original_line = 1; - let mut out = String::new(); - mappings.iter().fold(String::new(), |acc, mapping| { - if let Some(original) = &mapping.original { - if last_written_line == mapping.generated_line { - // avoid writing multiple original mappings per line - return acc; - } - out.clear(); - last_written_line = mapping.generated_line; - if mapping.generated_line == current_line + 1 { - current_line = mapping.generated_line; - if original.source_index == current_source_index { - if original.original_line == current_original_line + 1 { - current_original_line = original.original_line; - out.push_str(";AACA"); - return acc + &out; - } else { - out.push_str(";AA"); - encode(&mut out, original.original_line, current_original_line); - current_original_line = original.original_line; - out.push('A'); - return acc + &out; - } - } else { - out.push_str(";A"); - encode(&mut out, original.source_index, current_source_index); - current_source_index = original.source_index; - encode(&mut out, original.original_line, current_original_line); - current_original_line = original.original_line; - out.push('A'); - return acc + &out; - } - } else { - (0..mapping.generated_line - current_line).for_each(|_| out.push(';')); - current_line = mapping.generated_line; - if original.source_index == current_source_index { - if original.original_line == current_original_line + 1 { - current_original_line = original.original_line; - out.push_str("AACA"); - return acc + &out; - } else { - out.push_str("AA"); - encode(&mut out, original.original_line, current_original_line); - current_original_line = original.original_line; - out.push('A'); - return acc + &out; - } - } else { - out.push('A'); - encode(&mut out, original.source_index, current_source_index); - current_source_index = original.source_index; - encode(&mut out, original.original_line, current_original_line); - current_original_line = original.original_line; - out.push('A'); - return acc + &out; - } - } - } - // avoid writing generated mappings at all - acc - }) -} - pub struct PotentialTokens<'a> { bytes: &'a [u8], source: &'a str, @@ -1387,14 +1235,15 @@ pub fn stream_and_get_source_and_map<'a, S: StreamChunks<'a>>( on_source: OnSource<'_, 'a>, on_name: OnName<'_, 'a>, ) -> (GeneratedInfo, Option) { - let mut mappings = Vec::new(); + let mut mappings_encoder = create_encoder(options.columns); let mut sources: Vec> = Vec::new(); let mut sources_content: Vec> = Vec::new(); let mut names: Vec> = Vec::new(); + let generated_info = input_source.stream_chunks( options, &mut |chunk, mapping| { - mappings.push(mapping.clone()); + mappings_encoder.encode(&mapping); on_chunk(chunk, mapping); }, &mut |source_index, source, source_content| { @@ -1421,7 +1270,7 @@ pub fn stream_and_get_source_and_map<'a, S: StreamChunks<'a>>( }, ); - let mappings = encode_mappings(&mappings, options); + let mappings = mappings_encoder.drain(); let map = if mappings.is_empty() { None } else { diff --git a/src/lib.rs b/src/lib.rs index 1fb25039..8465a7f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ mod cached_source; mod concat_source; +mod encoder; mod error; mod helpers; mod original_source; @@ -11,6 +12,7 @@ mod source; mod source_map_source; mod vlq; mod with_indices; + pub use cached_source::CachedSource; pub use concat_source::ConcatSource; pub use error::{Error, Result}; From 428b47099fec76a594a714c52668338c43b40b27 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 22 Aug 2024 22:16:30 +0800 Subject: [PATCH 05/13] fix: revert --- src/helpers.rs | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a4648c4c..d74597ed 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,7 +2,8 @@ use arrayvec::ArrayVec; use rustc_hash::FxHashMap as HashMap; use std::{ borrow::{BorrowMut, Cow}, - cell::RefCell, + cell::{OnceCell, RefCell}, + rc::Rc, }; use crate::{ @@ -15,7 +16,7 @@ use crate::{ // Adding this type because sourceContentLine not happy type InnerSourceContentLine<'a> = - RefCell>>>>; + RefCell>>>>>; pub fn get_map<'a, S: StreamChunks<'a>>( stream: &'a S, @@ -749,7 +750,29 @@ fn stream_chunks_of_source_map_lines_full<'a>( #[derive(Debug)] struct SourceMapLineData<'a> { pub mappings_data: Vec, - pub chunks: Vec>>, + pub chunks: Vec>, +} + +#[derive(Debug)] +struct SourceMapLineChunk<'a> { + content: Cow<'a, str>, + cached: OnceCell>>, +} + +impl<'a> SourceMapLineChunk<'a> { + pub fn new(content: Cow<'a, str>) -> Self { + Self { + content, + cached: OnceCell::new(), + } + } + + pub fn substring(&self, start_index: usize, end_index: usize) -> &str { + let cached = self + .cached + .get_or_init(|| WithIndices::new(self.content.clone())); + cached.substring(start_index, end_index) + } } type InnerSourceIndexValueMapping<'a> = @@ -871,11 +894,11 @@ pub fn stream_chunks_of_combined_source_map<'a>( original_source_lines = if let Some(Some(original_source)) = inner_source_contents.get(&inner_source_index) { - Some( + Some(Rc::new( split_into_lines(original_source) .map(WithIndices::new) .collect(), - ) + )) } else { None }; @@ -973,10 +996,12 @@ pub fn stream_chunks_of_combined_source_map<'a>( .and_then(|original_source| { original_source.as_ref().map(|s| { let lines = split_into_lines(s); - lines - .into_iter() - .map(WithIndices::new) - .collect::>() + Rc::new( + lines + .into_iter() + .map(WithIndices::new) + .collect::>(), + ) }) }); inner_source_content_lines @@ -1181,7 +1206,7 @@ pub fn stream_chunks_of_combined_source_map<'a>( .unwrap_or(-1), ); // SAFETY: final_source is false - let chunk = WithIndices::new(chunk.unwrap()); + let chunk = SourceMapLineChunk::new(chunk.unwrap()); data.chunks.push(chunk); }, &mut |i, source, source_content| { From 488a9caeb4a11bd1c9d13fd9490b8aba363ae7e2 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 23 Aug 2024 00:00:09 +0800 Subject: [PATCH 06/13] perf: rm SourceMapLineChunk --- src/helpers.rs | 28 +++------------------------- src/replace_source.rs | 15 +++++---------- 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 86076667..69daf105 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,7 +2,7 @@ use arrayvec::ArrayVec; use rustc_hash::FxHashMap as HashMap; use std::{ borrow::{BorrowMut, Cow}, - cell::{OnceCell, RefCell}, + cell::RefCell, rc::Rc, }; @@ -902,29 +902,7 @@ fn stream_chunks_of_source_map_lines_full<'a>( #[derive(Debug)] struct SourceMapLineData<'a> { pub mappings_data: Vec, - pub chunks: Vec>, -} - -#[derive(Debug)] -struct SourceMapLineChunk<'a> { - content: Cow<'a, str>, - cached: OnceCell>>, -} - -impl<'a> SourceMapLineChunk<'a> { - pub fn new(content: Cow<'a, str>) -> Self { - Self { - content, - cached: OnceCell::new(), - } - } - - pub fn substring(&self, start_index: usize, end_index: usize) -> &str { - let cached = self - .cached - .get_or_init(|| WithIndices::new(self.content.clone())); - cached.substring(start_index, end_index) - } + pub chunks: Vec>>, } type InnerSourceIndexValueMapping<'a> = @@ -1358,7 +1336,7 @@ pub fn stream_chunks_of_combined_source_map<'a>( .unwrap_or(-1), ); // SAFETY: final_source is false - let chunk = SourceMapLineChunk::new(chunk.unwrap()); + let chunk = WithIndices::new(chunk.unwrap()); data.chunks.push(chunk); }, &mut |i, source, source_content| { diff --git a/src/replace_source.rs b/src/replace_source.rs index ab140093..8c0c12a6 100644 --- a/src/replace_source.rs +++ b/src/replace_source.rs @@ -278,7 +278,8 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { RefCell::new(Vec::new()); let name_mapping: RefCell, u32>> = RefCell::new(HashMap::default()); - let name_index_mapping: RefCell> = RefCell::new(Vec::new()); + let name_index_mapping: RefCell> = + RefCell::new(HashMap::default()); // check if source_content[line][col] is equal to expect // Why this is needed? @@ -404,10 +405,7 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { original_line: original.original_line, original_column: original.original_column, name_index: original.name_index.and_then(|name_index| { - name_index_mapping - .borrow() - .get(name_index as usize) - .copied() + name_index_mapping.borrow().get(&name_index).copied() }), } }), @@ -582,10 +580,7 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { original_line: original.original_line, original_column: original.original_column, name_index: original.name_index.and_then(|name_index| { - name_index_mapping - .borrow() - .get(name_index as usize) - .copied() + name_index_mapping.borrow().get(&name_index).copied() }), } }), @@ -614,7 +609,7 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { } name_index_mapping .borrow_mut() - .insert(name_index as usize, global_index.unwrap()); + .insert(name_index, global_index.unwrap()); }, ); From 728629dbc033f863a4e89d0028325f45ffe61f41 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 23 Aug 2024 00:17:17 +0800 Subject: [PATCH 07/13] perf: reduce allocation in replace source --- src/replace_source.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/replace_source.rs b/src/replace_source.rs index 8c0c12a6..d4bcfe89 100644 --- a/src/replace_source.rs +++ b/src/replace_source.rs @@ -430,7 +430,6 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { // Insert replacement content split into chunks by lines let repl = &repls[i]; - let lines: Vec<&str> = split_into_lines(&repl.content).collect(); let mut replacement_name_index = mapping .original .as_ref() @@ -448,7 +447,8 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { } replacement_name_index = global_index; } - for (m, content_line) in lines.iter().enumerate() { + let mut consumed_len = 0; + for content_line in split_into_lines(&repl.content) { on_chunk( Some(Cow::Owned(content_line.to_string())), Mapping { @@ -471,8 +471,10 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { ); // Only the first chunk has name assigned replacement_name_index = None; - - if m == lines.len() - 1 && !content_line.ends_with('\n') { + consumed_len += content_line.len(); + if consumed_len == repl.content.len() + && !content_line.ends_with('\n') + { if generated_column_offset_line == line { generated_column_offset += content_line.len() as i64; } else { From 86266510f30ddfe8077ff53ac280adae0eae90db Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 23 Aug 2024 10:09:46 +0800 Subject: [PATCH 08/13] perf: stream_chunks_of_source_map_full --- src/helpers.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 69daf105..97d74fe3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -681,7 +681,7 @@ fn stream_chunks_of_source_map_full<'a>( let mut current_mapping = mappings_iter.next(); for (current_generated_index, c) in source.char_indices() { - if let Some(mapping) = current_mapping.take() { + if let Some(mapping) = current_mapping { if mapping.generated_line == current_generated_line && mapping.generated_column == current_generated_column { @@ -703,8 +703,6 @@ fn stream_chunks_of_source_map_full<'a>( tracking_mapping_original = mapping.original; current_mapping = mappings_iter.next(); - } else { - current_mapping = Some(mapping); } } From 00cb1f49e78e30f26f8202599cb3e0cec77aafa2 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 23 Aug 2024 13:11:17 +0800 Subject: [PATCH 09/13] perf: refactor SegmentIter --- src/helpers.rs | 93 ++++++++++++++++++++++++-------------------------- src/vlq.rs | 6 ++-- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 97d74fe3..4b754ca4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -118,80 +118,75 @@ pub fn decode_mappings<'b, 'a: 'b>( } pub struct SegmentIter<'a> { - mapping_str: &'a str, + mapping_str: &'a [u8], generated_line: usize, generated_column: u32, source_index: u32, original_line: u32, original_column: u32, name_index: u32, - line: &'a str, nums: ArrayVec, - segment_cursor: usize, + tracing_index: usize, + current_index: usize, } impl<'a> SegmentIter<'a> { pub fn new(mapping_str: &'a str) -> Self { SegmentIter { - line: "", - mapping_str, + mapping_str: mapping_str.as_bytes(), source_index: 0, original_line: 1, original_column: 0, name_index: 0, - generated_line: 0, - segment_cursor: 0, + generated_line: 1, generated_column: 0, nums: ArrayVec::new(), + tracing_index: 0, + current_index: 0, } } - fn next_segment(&mut self) -> Option<&'a str> { - if self.line.is_empty() { - loop { - match self.next_line() { - Some(line) => { - self.generated_line += 1; - if line.is_empty() { - continue; - } - self.line = line; - self.generated_column = 0; - self.segment_cursor = 0; - break; + fn next_segment(&mut self) -> Option<&'a [u8]> { + let mapping_str_len = self.mapping_str.len(); + if self.current_index == mapping_str_len { + return None; + } + + loop { + match self.mapping_str[self.current_index] { + b',' => { + if self.tracing_index != self.current_index { + let segment = + &self.mapping_str[self.tracing_index..self.current_index]; + self.tracing_index = self.current_index; + return Some(segment); } - None => return None, + self.current_index += 1; + self.tracing_index = self.current_index; } + b';' => { + if self.tracing_index != self.current_index { + let segment = + &self.mapping_str[self.tracing_index..self.current_index]; + self.tracing_index = self.current_index; + return Some(segment); + } + self.generated_line += 1; + self.generated_column = 0; + self.current_index += 1; + self.tracing_index = self.current_index; + } + _ => self.current_index += 1, } - } - - if let Some(i) = - memchr::memchr(b',', self.line[self.segment_cursor..].as_bytes()) - { - let cursor = self.segment_cursor; - self.segment_cursor = self.segment_cursor + i + 1; - Some(&self.line[cursor..cursor + i]) - } else { - let line = self.line; - self.line = ""; - Some(&line[self.segment_cursor..]) - } - } - fn next_line(&mut self) -> Option<&'a str> { - if self.mapping_str.is_empty() { - return None; - } - match memchr::memchr(b';', self.mapping_str.as_bytes()) { - Some(i) => { - let temp_str = self.mapping_str; - self.mapping_str = &self.mapping_str[i + 1..]; - Some(&temp_str[..i]) - } - None => { - let tem_str = self.mapping_str; - self.mapping_str = ""; - Some(tem_str) + if self.current_index == mapping_str_len { + if self.tracing_index != self.current_index { + let segment = + &self.mapping_str[self.tracing_index..self.current_index]; + return Some(segment); + } else { + return None; + } } } } diff --git a/src/vlq.rs b/src/vlq.rs index 419dcff4..901dea5a 100644 --- a/src/vlq.rs +++ b/src/vlq.rs @@ -267,12 +267,12 @@ const B64: [i8; 256] = [ ]; /// Parses a VLQ segment into a pre-allocated `Vec` instead of returning a new allocation. -pub fn decode(segment: &str, rv: &mut ArrayVec) -> Result<()> { +pub fn decode(segment: &[u8], rv: &mut ArrayVec) -> Result<()> { let mut cur = 0; let mut shift = 0; - for c in segment.bytes() { - let enc = i64::from(B64[c as usize]); + for c in segment { + let enc = i64::from(B64[*c as usize]); let val = enc & 0b11111; let cont = enc >> 5; cur += val.checked_shl(shift).ok_or(Error::VlqOverflow)?; From 0ac24854651506308c0fd32b9454f3735b5b0365 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 23 Aug 2024 13:51:17 +0800 Subject: [PATCH 10/13] perf: decode_mappings --- src/helpers.rs | 16 ++++++++-------- src/source.rs | 11 +++-------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 4b754ca4..2edef116 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -111,9 +111,9 @@ pub struct GeneratedInfo { pub generated_column: u32, } -pub fn decode_mappings<'b, 'a: 'b>( - source_map: &'a SourceMap, -) -> impl Iterator + 'b { +pub fn decode_mappings( + source_map: &SourceMap, +) -> impl Iterator + '_ { SegmentIter::new(source_map.mappings()) } @@ -640,7 +640,7 @@ fn stream_chunks_of_source_map_final<'a>( } }; for mapping in source_map.decoded_mappings() { - on_mapping(mapping); + on_mapping(&mapping); } result } @@ -672,11 +672,11 @@ fn stream_chunks_of_source_map_full<'a>( let mut tracking_generated_column: u32 = 0; let mut tracking_mapping_original: Option = None; - let mut mappings_iter = source_map.decoded_mappings().iter(); + let mut mappings_iter = source_map.decoded_mappings(); let mut current_mapping = mappings_iter.next(); for (current_generated_index, c) in source.char_indices() { - if let Some(mapping) = current_mapping { + if let Some(mapping) = ¤t_mapping { if mapping.generated_line == current_generated_line && mapping.generated_column == current_generated_column { @@ -794,7 +794,7 @@ fn stream_chunks_of_source_map_lines_final<'a>( } }; for mapping in source_map.decoded_mappings() { - on_mapping(mapping); + on_mapping(&mapping); } result } @@ -864,7 +864,7 @@ fn stream_chunks_of_source_map_lines_full<'a>( } }; for mapping in source_map.decoded_mappings() { - on_mapping(mapping); + on_mapping(&mapping); } while current_generated_line as usize <= lines.len() { let chunk = lines[current_generated_line as usize - 1]; diff --git a/src/source.rs b/src/source.rs index 38dc1332..e5bdf188 100644 --- a/src/source.rs +++ b/src/source.rs @@ -4,7 +4,7 @@ use std::{ convert::{TryFrom, TryInto}, fmt, hash::{Hash, Hasher}, - sync::{Arc, OnceLock}, + sync::Arc, }; use dyn_clone::DynClone; @@ -194,7 +194,6 @@ pub struct SourceMap { sources_content: Vec>, names: Vec>, source_root: Option, - decoded_mappings: OnceLock>, } impl Hash for SourceMap { @@ -224,7 +223,6 @@ impl SourceMap { sources_content, names, source_root: None, - decoded_mappings: Default::default(), } } @@ -239,10 +237,8 @@ impl SourceMap { } /// Get the decoded mappings in [SourceMap]. - pub fn decoded_mappings(&'_ self) -> &[Mapping] { - self - .decoded_mappings - .get_or_init(|| decode_mappings(self).collect::>()) + pub fn decoded_mappings(&self) -> impl Iterator + '_ { + decode_mappings(self) } /// Get the mappings string in [SourceMap]. @@ -433,7 +429,6 @@ impl TryFrom for SourceMap { sources_content, names, source_root: raw.source_root, - decoded_mappings: Default::default(), }) } } From 6ad4e2d2bb59aa2c51645439c087377e19a31cbc Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 23 Aug 2024 14:52:56 +0800 Subject: [PATCH 11/13] fix: remove cache in replace_source --- src/replace_source.rs | 20 ++------------------ src/vlq.rs | 2 +- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/replace_source.rs b/src/replace_source.rs index ccbb297b..7af9eef3 100644 --- a/src/replace_source.rs +++ b/src/replace_source.rs @@ -4,7 +4,7 @@ use std::{ hash::{Hash, Hasher}, sync::{ atomic::{AtomicBool, Ordering}, - Arc, Mutex, MutexGuard, OnceLock, + Arc, Mutex, MutexGuard, }, }; @@ -36,7 +36,6 @@ use crate::{ /// ``` pub struct ReplaceSource { inner: Arc, - inner_source_code: OnceLock>, replacements: Mutex>, /// Whether `replacements` is sorted. is_sorted: AtomicBool, @@ -86,7 +85,6 @@ impl ReplaceSource { pub fn new(source: T) -> Self { Self { inner: Arc::new(source), - inner_source_code: OnceLock::new(), replacements: Mutex::new(Vec::new()), is_sorted: AtomicBool::new(true), } @@ -113,12 +111,6 @@ impl ReplaceSource { } impl ReplaceSource { - fn get_inner_source_code(&self) -> &str { - self - .inner_source_code - .get_or_init(|| Box::from(self.inner.source())) - } - /// Insert a content at start. pub fn insert(&mut self, start: u32, content: &str, name: Option<&str>) { self.replace(start, start, content, name) @@ -177,7 +169,7 @@ impl Source for ReplaceSource { fn source(&self) -> Cow { self.sort_replacement(); - let inner_source_code = self.get_inner_source_code(); + let inner_source_code = self.inner.source(); // mut_string_push_str is faster that vec join // concatenate strings benchmark, see https://github.com/hoodie/concatenation_benchmarks-rs @@ -239,13 +231,6 @@ impl std::fmt::Debug for ReplaceSource { ) -> Result<(), std::fmt::Error> { f.debug_struct("ReplaceSource") .field("inner", self.inner.as_ref()) - .field( - "inner_source_code", - &self - .inner_source_code - .get() - .map(|s| s.chars().take(50).collect::()), - ) .field( "replacements", &self.replacements.lock().iter().take(3).collect::>(), @@ -682,7 +667,6 @@ impl Clone for ReplaceSource { fn clone(&self) -> Self { Self { inner: self.inner.clone(), - inner_source_code: self.inner_source_code.clone(), replacements: Mutex::new(self.replacements().clone()), is_sorted: AtomicBool::new(self.is_sorted.load(Ordering::SeqCst)), } diff --git a/src/vlq.rs b/src/vlq.rs index 901dea5a..dd17b353 100644 --- a/src/vlq.rs +++ b/src/vlq.rs @@ -135,7 +135,7 @@ const B64: [i8; 256] = [ -1, -1, -1, - -1 - 1, + -1, -1, -1, -1, From eb5a825b323b5d072e351f176a3ddcf4ba16ce1d Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Sat, 24 Aug 2024 01:18:05 +0800 Subject: [PATCH 12/13] fix: remove decoded mappings --- src/helpers.rs | 48 ++++++++++++++---------------------------------- src/source.rs | 11 +++-------- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 05a1f91e..daffad37 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -466,20 +466,20 @@ fn stream_chunks_of_source_map_final<'a>( on_name(i as u32, Cow::Borrowed(name)); } let mut mapping_active_line = 0; - let mut on_mapping = |mapping: &Mapping| { + let mut on_mapping = |mapping: Mapping| { if mapping.generated_line >= result.generated_line && (mapping.generated_column >= result.generated_column || mapping.generated_line > result.generated_line) { return; } - if let Some(original) = &mapping.original { + if let Some(original) = mapping.original { on_chunk( None, Mapping { generated_line: mapping.generated_line, generated_column: mapping.generated_column, - original: Some(*original), + original: Some(original), }, ); mapping_active_line = mapping.generated_line; @@ -527,7 +527,7 @@ fn stream_chunks_of_source_map_full<'a>( let mut tracking_generated_column: u32 = 0; let mut tracking_mapping_original: Option = None; - let mut mappings_iter = source_map.decoded_mappings().iter(); + let mut mappings_iter = source_map.decoded_mappings(); let mut current_mapping = mappings_iter.next(); for (current_generated_index, c) in source.char_indices() { @@ -629,25 +629,15 @@ fn stream_chunks_of_source_map_lines_final<'a>( }; let mut current_generated_line = 1; - let mut on_mapping = |mapping: &Mapping| { - if let Some(original) = &mapping.original.filter(|_| { + let mut on_mapping = |mut mapping: Mapping| { + if let Some(mut original) = mapping.original.filter(|_| { current_generated_line <= mapping.generated_line && mapping.generated_line <= final_line }) { - on_chunk( - None, - Mapping { - generated_line: mapping.generated_line, - generated_column: 0, - original: Some(OriginalLocation { - source_index: original.source_index, - original_line: original.original_line, - original_column: original.original_column, - name_index: None, - }), - }, - ); + mapping.generated_column = 0; + original.name_index = None; current_generated_line = mapping.generated_line + 1; + on_chunk(None, mapping); } }; for mapping in source_map.decoded_mappings() { @@ -678,7 +668,7 @@ fn stream_chunks_of_source_map_lines_full<'a>( ) } let mut current_generated_line = 1; - let mut on_mapping = |mapping: &Mapping| { + let mut on_mapping = |mut mapping: Mapping| { if mapping.original.is_none() || mapping.generated_line < current_generated_line || mapping.generated_line as usize > lines.len() @@ -699,24 +689,14 @@ fn stream_chunks_of_source_map_lines_full<'a>( } current_generated_line += 1; } - if let Some(original) = &mapping + if let Some(mut original) = mapping .original .filter(|_| mapping.generated_line as usize <= lines.len()) { let chunk = lines[current_generated_line as usize - 1]; - on_chunk( - Some(Cow::Borrowed(chunk)), - Mapping { - generated_line: mapping.generated_line, - generated_column: 0, - original: Some(OriginalLocation { - source_index: original.source_index, - original_line: original.original_line, - original_column: original.original_column, - name_index: None, - }), - }, - ); + mapping.generated_column = 0; + original.name_index = None; + on_chunk(Some(Cow::Borrowed(chunk)), mapping); current_generated_line += 1; } }; diff --git a/src/source.rs b/src/source.rs index 38dc1332..e5bdf188 100644 --- a/src/source.rs +++ b/src/source.rs @@ -4,7 +4,7 @@ use std::{ convert::{TryFrom, TryInto}, fmt, hash::{Hash, Hasher}, - sync::{Arc, OnceLock}, + sync::Arc, }; use dyn_clone::DynClone; @@ -194,7 +194,6 @@ pub struct SourceMap { sources_content: Vec>, names: Vec>, source_root: Option, - decoded_mappings: OnceLock>, } impl Hash for SourceMap { @@ -224,7 +223,6 @@ impl SourceMap { sources_content, names, source_root: None, - decoded_mappings: Default::default(), } } @@ -239,10 +237,8 @@ impl SourceMap { } /// Get the decoded mappings in [SourceMap]. - pub fn decoded_mappings(&'_ self) -> &[Mapping] { - self - .decoded_mappings - .get_or_init(|| decode_mappings(self).collect::>()) + pub fn decoded_mappings(&self) -> impl Iterator + '_ { + decode_mappings(self) } /// Get the mappings string in [SourceMap]. @@ -433,7 +429,6 @@ impl TryFrom for SourceMap { sources_content, names, source_root: raw.source_root, - decoded_mappings: Default::default(), }) } } From 83caf87bc4db0be91e8b5e3b09b72f177eb42252 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Sat, 24 Aug 2024 18:16:03 +0800 Subject: [PATCH 13/13] perf: next_segment --- src/helpers.rs | 127 ++++++++++++++++++++++-------------------- src/replace_source.rs | 4 +- src/vlq.rs | 73 +++++++++++++++--------- 3 files changed, 115 insertions(+), 89 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7ba43f38..030b4640 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,10 +1,10 @@ -use arrayvec::ArrayVec; use std::{ borrow::{BorrowMut, Cow}, cell::RefCell, rc::Rc, }; +use memchr::Memchr2; use rustc_hash::FxHashMap as HashMap; use crate::{ @@ -13,7 +13,7 @@ use crate::{ source::{Mapping, OriginalLocation}, vlq::decode, with_indices::WithIndices, - MapOptions, SourceMap, + Error, MapOptions, SourceMap, }; // Adding this type because sourceContentLine not happy @@ -123,81 +123,78 @@ pub fn decode_mappings( pub struct SegmentIter<'a> { mapping_str: &'a [u8], + mapping_iter: Memchr2<'a>, generated_line: usize, generated_column: u32, source_index: u32, original_line: u32, original_column: u32, name_index: u32, - nums: ArrayVec, tracing_index: usize, - current_index: usize, + tracing_newline: bool, } impl<'a> SegmentIter<'a> { pub fn new(mapping_str: &'a str) -> Self { + let mapping_str = mapping_str.as_bytes(); + let mapping_iter = memchr::memchr2_iter(b',', b';', mapping_str); SegmentIter { - mapping_str: mapping_str.as_bytes(), + mapping_str, + mapping_iter, source_index: 0, original_line: 1, original_column: 0, name_index: 0, generated_line: 1, generated_column: 0, - nums: ArrayVec::new(), tracing_index: 0, - current_index: 0, + tracing_newline: false, } } fn next_segment(&mut self) -> Option<&'a [u8]> { let mapping_str_len = self.mapping_str.len(); - if self.current_index == mapping_str_len { - return None; - } loop { - match self.mapping_str[self.current_index] { - b',' => { - if self.tracing_index != self.current_index { - let segment = - &self.mapping_str[self.tracing_index..self.current_index]; - self.tracing_index = self.current_index; - return Some(segment); + if self.tracing_newline { + self.generated_line += 1; + self.generated_column = 0; + self.tracing_newline = false; + } + + match self.mapping_iter.next() { + Some(index) => match self.mapping_str[index] { + b',' => { + if self.tracing_index != index { + let segment = &self.mapping_str[self.tracing_index..index]; + self.tracing_index = index + 1; + return Some(segment); + } + self.tracing_index = index + 1; } - self.current_index += 1; - self.tracing_index = self.current_index; - } - b';' => { - if self.tracing_index != self.current_index { + b';' => { + self.tracing_newline = true; + if self.tracing_index != index { + let segment = &self.mapping_str[self.tracing_index..index]; + self.tracing_index = index + 1; + return Some(segment); + } + self.tracing_index = index + 1; + } + _ => unreachable!(), + }, + None => { + if self.tracing_index != mapping_str_len { let segment = - &self.mapping_str[self.tracing_index..self.current_index]; - self.tracing_index = self.current_index; + &self.mapping_str[self.tracing_index..mapping_str_len]; + self.tracing_index = mapping_str_len; return Some(segment); } - self.generated_line += 1; - self.generated_column = 0; - self.current_index += 1; - self.tracing_index = self.current_index; } - _ => match memchr::memchr2( - b',', - b';', - &self.mapping_str[self.current_index..], - ) { - Some(index) => self.current_index += index, - None => self.current_index = mapping_str_len, - }, } - if self.current_index == mapping_str_len { - if self.tracing_index != self.current_index { - let segment = - &self.mapping_str[self.tracing_index..self.current_index]; - return Some(segment); - } else { - return None; - } + if self.tracing_index == mapping_str_len { + return None; } } } @@ -209,30 +206,38 @@ impl<'a> Iterator for SegmentIter<'a> { fn next(&mut self) -> Option { match self.next_segment() { Some(segment) => { - self.nums.clear(); - decode(segment, &mut self.nums).unwrap(); - self.generated_column = - (i64::from(self.generated_column) + self.nums[0]) as u32; + let mut vlq = decode(segment); + self.generated_column = (i64::from(self.generated_column) + + vlq + .next() + .unwrap_or_else(|| Err(Error::VlqNoValues)) + .unwrap()) as u32; let mut src = None; let mut name = None; - if self.nums.len() > 1 { - if self.nums.len() != 4 && self.nums.len() != 5 { - panic!("got {} segments, expected 4 or 5", self.nums.len()); - } + if let Some(source_index) = vlq.next() { + // if self.nums.len() != 4 && self.nums.len() != 5 { + // panic!("got {} segments, expected 4 or 5", self.nums.len()); + // } self.source_index = - (i64::from(self.source_index) + self.nums[1]) as u32; + (i64::from(self.source_index) + source_index.unwrap()) as u32; src = Some(self.source_index); - self.original_line = - (i64::from(self.original_line) + self.nums[2]) as u32; - self.original_column = - (i64::from(self.original_column) + self.nums[3]) as u32; - - if self.nums.len() > 4 { + self.original_line = (i64::from(self.original_line) + + vlq + .next() + .unwrap_or_else(|| Err(Error::VlqNoValues)) + .unwrap()) as u32; + self.original_column = (i64::from(self.original_column) + + vlq + .next() + .unwrap_or_else(|| Err(Error::VlqNoValues)) + .unwrap()) as u32; + + if let Some(name_index) = vlq.next() { self.name_index = - (i64::from(self.name_index) + self.nums[4]) as u32; - name = Some(self.name_index); + (i64::from(self.name_index) + name_index.unwrap()) as u32; + name = Some(self.name_index) } } diff --git a/src/replace_source.rs b/src/replace_source.rs index 3de899ed..8e7b613b 100644 --- a/src/replace_source.rs +++ b/src/replace_source.rs @@ -263,8 +263,8 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource { RefCell::new(LinearMap::default()); let name_mapping: RefCell, u32>> = RefCell::new(HashMap::default()); - let name_index_mapping: RefCell> = - RefCell::new(HashMap::default()); + let name_index_mapping: RefCell> = + RefCell::new(LinearMap::default()); // check if source_content[line][col] is equal to expect // Why this is needed? diff --git a/src/vlq.rs b/src/vlq.rs index ae820ac1..1741c6db 100644 --- a/src/vlq.rs +++ b/src/vlq.rs @@ -1,8 +1,6 @@ //! Implements utilities for dealing with the sourcemap vlq encoding. //! forked from [rust-sourcemap](https://github.com/getsentry/rust-sourcemap/blob/851f12bfa6c4cf2c737b94734b27f7d9bfb4de86/src/vlq.rs) -use arrayvec::ArrayVec; - use crate::{Error, Result}; const B64_CHARS: &[u8] = @@ -24,36 +22,59 @@ const B64: [i8; 256] = [ -1, -1, -1, -1, -1, -1, ]; -/// Parses a VLQ segment into a pre-allocated `Vec` instead of returning a new allocation. -pub fn decode(segment: &[u8], rv: &mut ArrayVec) -> Result<()> { - let mut cur = 0; - let mut shift = 0; +pub struct VlqIter<'a> { + segment: std::slice::Iter<'a, u8>, + cur: i64, + shift: u32, +} + +impl<'a> Iterator for VlqIter<'a> { + type Item = Result; - for c in segment { - let enc = i64::from(B64[*c as usize]); - let val = enc & 0b11111; - let cont = enc >> 5; - cur += val.checked_shl(shift).ok_or(Error::VlqOverflow)?; - shift += 5; + fn next(&mut self) -> Option { + loop { + let c = self.segment.next(); + match c { + Some(c) => { + let enc = i64::from(B64[*c as usize]); + let val = enc & 0b11111; + let cont = enc >> 5; + self.cur += + match val.checked_shl(self.shift).ok_or(Error::VlqOverflow) { + Ok(v) => v, + Err(e) => return Some(Err(e)), + }; + self.shift += 5; - if cont == 0 { - let sign = cur & 1; - cur >>= 1; - if sign != 0 { - cur = -cur; + if cont == 0 { + let sign = self.cur & 1; + self.cur >>= 1; + if sign != 0 { + self.cur = -self.cur; + } + let result = self.cur; + self.cur = 0; + self.shift = 0; + return Some(Ok(result)); + } + } + None => { + if self.cur != 0 || self.shift != 0 { + return Some(Err(Error::VlqLeftover)); + } else { + return None; + } + } } - rv.push(cur); - cur = 0; - shift = 0; } } +} - if cur != 0 || shift != 0 { - Err(Error::VlqLeftover) - } else if rv.is_empty() { - Err(Error::VlqNoValues) - } else { - Ok(()) +pub fn decode(segment: &[u8]) -> VlqIter<'_> { + VlqIter { + segment: segment.iter(), + cur: 0, + shift: 0, } }