Skip to content

Commit

Permalink
perf: SegmentIter
Browse files Browse the repository at this point in the history
  • Loading branch information
SyMind committed Aug 26, 2024
1 parent 95a493c commit 67c554c
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 130 deletions.
187 changes: 89 additions & 98 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use arrayvec::ArrayVec;
use core::fmt;
use std::{
borrow::{BorrowMut, Cow},
cell::{OnceCell, RefCell},
cell::RefCell,
rc::Rc,
};

Expand All @@ -13,7 +14,7 @@ use crate::{
source::{Mapping, OriginalLocation},
vlq::decode,
with_indices::WithIndices,
MapOptions, SourceMap,
Error, MapOptions, SourceMap,
};

// Adding this type because sourceContentLine not happy
Expand Down Expand Up @@ -115,87 +116,89 @@ pub struct GeneratedInfo {
pub generated_column: u32,
}

pub fn decode_mappings<'b, 'a: 'b>(
source_map: &'a SourceMap,
) -> impl Iterator<Item = Mapping> + 'b {
pub fn decode_mappings(
source_map: &SourceMap,
) -> impl Iterator<Item = Mapping> + '_ {
SegmentIter::new(source_map.mappings())
}

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<i64, 5>,
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);
}
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);
}
None => return None,
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 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;
}
}
}
}
Expand All @@ -208,29 +211,41 @@ impl<'a> Iterator for SegmentIter<'a> {
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.name_index =
(i64::from(self.name_index) + self.nums[4]) as u32;
name = Some(self.name_index);
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;

match vlq.next() {
Some(name_index) => {
self.name_index =
(i64::from(self.name_index) + name_index.unwrap()) as u32;
name = Some(self.name_index)
}
None => (),
}
}

Expand Down Expand Up @@ -531,7 +546,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
{
Expand All @@ -553,8 +568,6 @@ fn stream_chunks_of_source_map_full<'a>(
tracking_mapping_original = mapping.original;

current_mapping = mappings_iter.next();
} else {
current_mapping = Some(mapping);
}
}

Expand Down Expand Up @@ -732,29 +745,7 @@ fn stream_chunks_of_source_map_lines_full<'a>(
#[derive(Debug)]
struct SourceMapLineData<'a> {
pub mappings_data: Vec<i64>,
pub chunks: Vec<SourceMapLineChunk<'a>>,
}

#[derive(Debug)]
struct SourceMapLineChunk<'a> {
content: Cow<'a, str>,
cached: OnceCell<WithIndices<Cow<'a, str>>>,
}

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<WithIndices<Cow<'a, str>>>,
}

type InnerSourceIndexValueMapping<'a> =
Expand Down Expand Up @@ -1203,7 +1194,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| {
Expand Down
86 changes: 54 additions & 32 deletions src/vlq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,56 +24,78 @@ 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: &str, rv: &mut ArrayVec<i64, 5>) -> 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<i64>;

for c in segment.bytes() {
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<Self::Item> {
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<'a>(segment: &'a [u8]) -> VlqIter<'a> {
VlqIter {
segment: segment.iter(),
cur: 0,
shift: 0,
}
}

#[inline(always)]
pub fn encode(out: &mut Vec<u8>, a: u32, b: u32) {
let mut num = if a >= b {
(a - b) << 1
} else {
((b - a) << 1) + 1
};
fn encode_vlq(out: &mut String, num: i64) {
let mut num = if num < 0 { ((-num) << 1) + 1 } else { num << 1 };

loop {
let mut digit = num & 0b11111;
num >>= 5;
if num > 0 {
digit |= 1 << 5;
}
out.push(B64_CHARS[digit as usize]);
out.push(B64_CHARS[digit as usize] as char);
if num == 0 {
break;
}
}
}

pub fn encode(out: &mut String, a: u32, b: u32) {
encode_vlq(out, i64::from(a) - i64::from(b))
}

0 comments on commit 67c554c

Please sign in to comment.