Skip to content

Commit 83caf87

Browse files
committed
perf: next_segment
1 parent 89e14f6 commit 83caf87

File tree

3 files changed

+115
-89
lines changed

3 files changed

+115
-89
lines changed

src/helpers.rs

+66-61
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use arrayvec::ArrayVec;
21
use std::{
32
borrow::{BorrowMut, Cow},
43
cell::RefCell,
54
rc::Rc,
65
};
76

7+
use memchr::Memchr2;
88
use rustc_hash::FxHashMap as HashMap;
99

1010
use crate::{
@@ -13,7 +13,7 @@ use crate::{
1313
source::{Mapping, OriginalLocation},
1414
vlq::decode,
1515
with_indices::WithIndices,
16-
MapOptions, SourceMap,
16+
Error, MapOptions, SourceMap,
1717
};
1818

1919
// Adding this type because sourceContentLine not happy
@@ -123,81 +123,78 @@ pub fn decode_mappings(
123123

124124
pub struct SegmentIter<'a> {
125125
mapping_str: &'a [u8],
126+
mapping_iter: Memchr2<'a>,
126127
generated_line: usize,
127128
generated_column: u32,
128129
source_index: u32,
129130
original_line: u32,
130131
original_column: u32,
131132
name_index: u32,
132-
nums: ArrayVec<i64, 5>,
133133
tracing_index: usize,
134-
current_index: usize,
134+
tracing_newline: bool,
135135
}
136136

137137
impl<'a> SegmentIter<'a> {
138138
pub fn new(mapping_str: &'a str) -> Self {
139+
let mapping_str = mapping_str.as_bytes();
140+
let mapping_iter = memchr::memchr2_iter(b',', b';', mapping_str);
139141
SegmentIter {
140-
mapping_str: mapping_str.as_bytes(),
142+
mapping_str,
143+
mapping_iter,
141144
source_index: 0,
142145
original_line: 1,
143146
original_column: 0,
144147
name_index: 0,
145148
generated_line: 1,
146149
generated_column: 0,
147-
nums: ArrayVec::new(),
148150
tracing_index: 0,
149-
current_index: 0,
151+
tracing_newline: false,
150152
}
151153
}
152154

153155
fn next_segment(&mut self) -> Option<&'a [u8]> {
154156
let mapping_str_len = self.mapping_str.len();
155-
if self.current_index == mapping_str_len {
156-
return None;
157-
}
158157

159158
loop {
160-
match self.mapping_str[self.current_index] {
161-
b',' => {
162-
if self.tracing_index != self.current_index {
163-
let segment =
164-
&self.mapping_str[self.tracing_index..self.current_index];
165-
self.tracing_index = self.current_index;
166-
return Some(segment);
159+
if self.tracing_newline {
160+
self.generated_line += 1;
161+
self.generated_column = 0;
162+
self.tracing_newline = false;
163+
}
164+
165+
match self.mapping_iter.next() {
166+
Some(index) => match self.mapping_str[index] {
167+
b',' => {
168+
if self.tracing_index != index {
169+
let segment = &self.mapping_str[self.tracing_index..index];
170+
self.tracing_index = index + 1;
171+
return Some(segment);
172+
}
173+
self.tracing_index = index + 1;
167174
}
168-
self.current_index += 1;
169-
self.tracing_index = self.current_index;
170-
}
171-
b';' => {
172-
if self.tracing_index != self.current_index {
175+
b';' => {
176+
self.tracing_newline = true;
177+
if self.tracing_index != index {
178+
let segment = &self.mapping_str[self.tracing_index..index];
179+
self.tracing_index = index + 1;
180+
return Some(segment);
181+
}
182+
self.tracing_index = index + 1;
183+
}
184+
_ => unreachable!(),
185+
},
186+
None => {
187+
if self.tracing_index != mapping_str_len {
173188
let segment =
174-
&self.mapping_str[self.tracing_index..self.current_index];
175-
self.tracing_index = self.current_index;
189+
&self.mapping_str[self.tracing_index..mapping_str_len];
190+
self.tracing_index = mapping_str_len;
176191
return Some(segment);
177192
}
178-
self.generated_line += 1;
179-
self.generated_column = 0;
180-
self.current_index += 1;
181-
self.tracing_index = self.current_index;
182193
}
183-
_ => match memchr::memchr2(
184-
b',',
185-
b';',
186-
&self.mapping_str[self.current_index..],
187-
) {
188-
Some(index) => self.current_index += index,
189-
None => self.current_index = mapping_str_len,
190-
},
191194
}
192195

193-
if self.current_index == mapping_str_len {
194-
if self.tracing_index != self.current_index {
195-
let segment =
196-
&self.mapping_str[self.tracing_index..self.current_index];
197-
return Some(segment);
198-
} else {
199-
return None;
200-
}
196+
if self.tracing_index == mapping_str_len {
197+
return None;
201198
}
202199
}
203200
}
@@ -209,30 +206,38 @@ impl<'a> Iterator for SegmentIter<'a> {
209206
fn next(&mut self) -> Option<Self::Item> {
210207
match self.next_segment() {
211208
Some(segment) => {
212-
self.nums.clear();
213-
decode(segment, &mut self.nums).unwrap();
214-
self.generated_column =
215-
(i64::from(self.generated_column) + self.nums[0]) as u32;
209+
let mut vlq = decode(segment);
210+
self.generated_column = (i64::from(self.generated_column)
211+
+ vlq
212+
.next()
213+
.unwrap_or_else(|| Err(Error::VlqNoValues))
214+
.unwrap()) as u32;
216215

217216
let mut src = None;
218217
let mut name = None;
219218

220-
if self.nums.len() > 1 {
221-
if self.nums.len() != 4 && self.nums.len() != 5 {
222-
panic!("got {} segments, expected 4 or 5", self.nums.len());
223-
}
219+
if let Some(source_index) = vlq.next() {
220+
// if self.nums.len() != 4 && self.nums.len() != 5 {
221+
// panic!("got {} segments, expected 4 or 5", self.nums.len());
222+
// }
224223
self.source_index =
225-
(i64::from(self.source_index) + self.nums[1]) as u32;
224+
(i64::from(self.source_index) + source_index.unwrap()) as u32;
226225
src = Some(self.source_index);
227-
self.original_line =
228-
(i64::from(self.original_line) + self.nums[2]) as u32;
229-
self.original_column =
230-
(i64::from(self.original_column) + self.nums[3]) as u32;
231-
232-
if self.nums.len() > 4 {
226+
self.original_line = (i64::from(self.original_line)
227+
+ vlq
228+
.next()
229+
.unwrap_or_else(|| Err(Error::VlqNoValues))
230+
.unwrap()) as u32;
231+
self.original_column = (i64::from(self.original_column)
232+
+ vlq
233+
.next()
234+
.unwrap_or_else(|| Err(Error::VlqNoValues))
235+
.unwrap()) as u32;
236+
237+
if let Some(name_index) = vlq.next() {
233238
self.name_index =
234-
(i64::from(self.name_index) + self.nums[4]) as u32;
235-
name = Some(self.name_index);
239+
(i64::from(self.name_index) + name_index.unwrap()) as u32;
240+
name = Some(self.name_index)
236241
}
237242
}
238243

src/replace_source.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ impl<'a, T: Source> StreamChunks<'a> for ReplaceSource<T> {
263263
RefCell::new(LinearMap::default());
264264
let name_mapping: RefCell<HashMap<Cow<str>, u32>> =
265265
RefCell::new(HashMap::default());
266-
let name_index_mapping: RefCell<HashMap<u32, u32>> =
267-
RefCell::new(HashMap::default());
266+
let name_index_mapping: RefCell<LinearMap<u32>> =
267+
RefCell::new(LinearMap::default());
268268

269269
// check if source_content[line][col] is equal to expect
270270
// Why this is needed?

src/vlq.rs

+47-26
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
//! Implements utilities for dealing with the sourcemap vlq encoding.
22
//! forked from [rust-sourcemap](https://github.com/getsentry/rust-sourcemap/blob/851f12bfa6c4cf2c737b94734b27f7d9bfb4de86/src/vlq.rs)
33
4-
use arrayvec::ArrayVec;
5-
64
use crate::{Error, Result};
75

86
const B64_CHARS: &[u8] =
@@ -24,36 +22,59 @@ const B64: [i8; 256] = [
2422
-1, -1, -1, -1, -1, -1,
2523
];
2624

27-
/// Parses a VLQ segment into a pre-allocated `Vec` instead of returning a new allocation.
28-
pub fn decode(segment: &[u8], rv: &mut ArrayVec<i64, 5>) -> Result<()> {
29-
let mut cur = 0;
30-
let mut shift = 0;
25+
pub struct VlqIter<'a> {
26+
segment: std::slice::Iter<'a, u8>,
27+
cur: i64,
28+
shift: u32,
29+
}
30+
31+
impl<'a> Iterator for VlqIter<'a> {
32+
type Item = Result<i64>;
3133

32-
for c in segment {
33-
let enc = i64::from(B64[*c as usize]);
34-
let val = enc & 0b11111;
35-
let cont = enc >> 5;
36-
cur += val.checked_shl(shift).ok_or(Error::VlqOverflow)?;
37-
shift += 5;
34+
fn next(&mut self) -> Option<Self::Item> {
35+
loop {
36+
let c = self.segment.next();
37+
match c {
38+
Some(c) => {
39+
let enc = i64::from(B64[*c as usize]);
40+
let val = enc & 0b11111;
41+
let cont = enc >> 5;
42+
self.cur +=
43+
match val.checked_shl(self.shift).ok_or(Error::VlqOverflow) {
44+
Ok(v) => v,
45+
Err(e) => return Some(Err(e)),
46+
};
47+
self.shift += 5;
3848

39-
if cont == 0 {
40-
let sign = cur & 1;
41-
cur >>= 1;
42-
if sign != 0 {
43-
cur = -cur;
49+
if cont == 0 {
50+
let sign = self.cur & 1;
51+
self.cur >>= 1;
52+
if sign != 0 {
53+
self.cur = -self.cur;
54+
}
55+
let result = self.cur;
56+
self.cur = 0;
57+
self.shift = 0;
58+
return Some(Ok(result));
59+
}
60+
}
61+
None => {
62+
if self.cur != 0 || self.shift != 0 {
63+
return Some(Err(Error::VlqLeftover));
64+
} else {
65+
return None;
66+
}
67+
}
4468
}
45-
rv.push(cur);
46-
cur = 0;
47-
shift = 0;
4869
}
4970
}
71+
}
5072

51-
if cur != 0 || shift != 0 {
52-
Err(Error::VlqLeftover)
53-
} else if rv.is_empty() {
54-
Err(Error::VlqNoValues)
55-
} else {
56-
Ok(())
73+
pub fn decode(segment: &[u8]) -> VlqIter<'_> {
74+
VlqIter {
75+
segment: segment.iter(),
76+
cur: 0,
77+
shift: 0,
5778
}
5879
}
5980

0 commit comments

Comments
 (0)