Skip to content

Commit 10b6a4c

Browse files
authored
perf: WithIndices (#150)
1 parent 9436375 commit 10b6a4c

File tree

4 files changed

+210
-77
lines changed

4 files changed

+210
-77
lines changed

src/decoder.rs

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ pub(crate) struct MappingsDecoder<'a> {
3939
current_value: i64,
4040
current_value_pos: usize,
4141
generated_line: u32,
42-
generated_column: i64,
4342
}
4443

4544
impl<'a> MappingsDecoder<'a> {
@@ -52,7 +51,6 @@ impl<'a> MappingsDecoder<'a> {
5251
current_value: 0,
5352
current_value_pos: 0,
5453
generated_line: 1,
55-
generated_column: -1,
5654
}
5755
}
5856
}
@@ -67,44 +65,39 @@ impl Iterator for MappingsDecoder<'_> {
6765
continue;
6866
}
6967
if (value & COM) != 0 {
70-
let mapping = match self.current_data_pos {
71-
1 => Some(Mapping {
72-
generated_line: self.generated_line,
73-
generated_column: self.current_data[0],
74-
original: None,
75-
}),
76-
4 => Some(Mapping {
77-
generated_line: self.generated_line,
78-
generated_column: self.current_data[0],
79-
original: Some(OriginalLocation {
68+
let mut mapping = Mapping {
69+
generated_line: self.generated_line,
70+
generated_column: self.current_data[0],
71+
original: None,
72+
};
73+
let current_data_pos = self.current_data_pos;
74+
self.current_data_pos = 0;
75+
if value == SEM {
76+
self.generated_line += 1;
77+
self.current_data[0] = 0;
78+
}
79+
match current_data_pos {
80+
1 => return Some(mapping),
81+
4 => {
82+
mapping.original = Some(OriginalLocation {
8083
source_index: self.current_data[1],
8184
original_line: self.current_data[2],
8285
original_column: self.current_data[3],
8386
name_index: None,
84-
}),
85-
}),
86-
5 => Some(Mapping {
87-
generated_line: self.generated_line,
88-
generated_column: self.current_data[0],
89-
original: Some(OriginalLocation {
87+
});
88+
return Some(mapping);
89+
}
90+
5 => {
91+
mapping.original = Some(OriginalLocation {
9092
source_index: self.current_data[1],
9193
original_line: self.current_data[2],
9294
original_column: self.current_data[3],
9395
name_index: Some(self.current_data[4]),
94-
}),
95-
}),
96-
_ => None,
96+
});
97+
return Some(mapping);
98+
}
99+
_ => (),
97100
};
98-
self.generated_column = self.current_data[0] as i64;
99-
self.current_data_pos = 0;
100-
if value == SEM {
101-
self.generated_line += 1;
102-
self.current_data[0] = 0;
103-
self.generated_column = -1;
104-
}
105-
if mapping.is_some() {
106-
return mapping;
107-
}
108101
} else if (value & CONTINUATION_BIT) == 0 {
109102
// last sextet
110103
self.current_value |= (value as i64) << self.current_value_pos;

src/helpers.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ pub trait SourceText<'a>: Default + Clone + ToString {
12521252
fn ends_with(&self, value: &str) -> bool;
12531253

12541254
/// Returns an iterator over the char indices in the text.
1255-
fn char_indices(&self) -> impl Iterator<Item = (usize, char)>;
1255+
fn char_indices(&self) -> impl DoubleEndedIterator<Item = (usize, char)>;
12561256

12571257
/// Gets the byte at the specified index, if it exists.
12581258
fn get_byte(&self, byte_index: usize) -> Option<u8>;
@@ -1289,7 +1289,7 @@ impl<'a> SourceText<'a> for Rope<'a> {
12891289
(*self).ends_with(value)
12901290
}
12911291

1292-
fn char_indices(&self) -> impl Iterator<Item = (usize, char)> {
1292+
fn char_indices(&self) -> impl DoubleEndedIterator<Item = (usize, char)> {
12931293
self.char_indices()
12941294
}
12951295

@@ -1331,7 +1331,7 @@ impl<'a> SourceText<'a> for &'a str {
13311331
(*self).ends_with(value)
13321332
}
13331333

1334-
fn char_indices(&self) -> impl Iterator<Item = (usize, char)> {
1334+
fn char_indices(&self) -> impl DoubleEndedIterator<Item = (usize, char)> {
13351335
(*self).char_indices()
13361336
}
13371337

src/rope.rs

Lines changed: 96 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
use std::{
44
borrow::Cow,
5-
collections::VecDeque,
65
hash::Hash,
76
ops::{Bound, RangeBounds},
87
rc::Rc,
@@ -134,13 +133,24 @@ impl<'a> Rope<'a> {
134133
iter: s.char_indices(),
135134
},
136135
},
137-
Repr::Full(data) => CharIndices {
138-
iter: CharIndicesEnum::Full {
139-
chunks: data,
140-
char_indices: VecDeque::new(),
141-
chunk_index: 0,
142-
},
143-
},
136+
Repr::Full(vec) => {
137+
let right_byte_offset = vec.iter().map(|(s, _)| s.len() as u32).sum();
138+
139+
CharIndices {
140+
iter: CharIndicesEnum::Full {
141+
iters: vec
142+
.iter()
143+
.map(|(s, _)| s.char_indices())
144+
.collect::<Vec<_>>(),
145+
left_chunk_index: 0,
146+
left_byte_offset: 0,
147+
last_left_indice: None,
148+
right_chunk_index: (vec.len() - 1) as u32,
149+
right_byte_offset,
150+
right_byte_offset_for: vec.len() as u32,
151+
},
152+
}
153+
}
144154
}
145155
}
146156

@@ -658,9 +668,13 @@ enum CharIndicesEnum<'a, 'b> {
658668
iter: std::str::CharIndices<'b>,
659669
},
660670
Full {
661-
chunks: &'a [(&'b str, usize)],
662-
char_indices: VecDeque<(usize, char)>,
663-
chunk_index: usize,
671+
iters: Vec<std::str::CharIndices<'a>>,
672+
left_chunk_index: u32,
673+
left_byte_offset: u32,
674+
last_left_indice: Option<(usize, char)>,
675+
right_chunk_index: u32,
676+
right_byte_offset: u32,
677+
right_byte_offset_for: u32,
664678
},
665679
}
666680

@@ -675,29 +689,59 @@ impl Iterator for CharIndices<'_, '_> {
675689
match &mut self.iter {
676690
CharIndicesEnum::Light { iter } => iter.next(),
677691
CharIndicesEnum::Full {
678-
chunks,
679-
char_indices,
680-
chunk_index,
692+
iters,
693+
left_chunk_index,
694+
left_byte_offset,
695+
last_left_indice,
696+
..
681697
} => {
682-
if let Some(item) = char_indices.pop_front() {
683-
return Some(item);
684-
}
685-
686-
if *chunk_index >= chunks.len() {
698+
if (*left_chunk_index as usize) >= iters.len() {
687699
return None;
688700
}
689-
690-
// skip empty chunks
691-
while *chunk_index < chunks.len() && chunks[*chunk_index].0.is_empty() {
692-
*chunk_index += 1;
701+
if let Some((byte_index, char)) =
702+
iters[*left_chunk_index as usize].next()
703+
{
704+
*last_left_indice = Some((byte_index, char));
705+
Some((byte_index + (*left_byte_offset as usize), char))
706+
} else {
707+
*left_chunk_index += 1;
708+
if let Some((byte_index, char)) = last_left_indice.take() {
709+
*left_byte_offset =
710+
*left_byte_offset + byte_index as u32 + char.len_utf8() as u32;
711+
}
712+
self.next()
693713
}
714+
}
715+
}
716+
}
717+
}
694718

695-
let (chunk, start_pos) = chunks[*chunk_index];
696-
697-
char_indices
698-
.extend(chunk.char_indices().map(|(i, c)| (start_pos + i, c)));
699-
*chunk_index += 1;
700-
char_indices.pop_front()
719+
impl DoubleEndedIterator for CharIndices<'_, '_> {
720+
fn next_back(&mut self) -> Option<Self::Item> {
721+
match &mut self.iter {
722+
CharIndicesEnum::Light { iter } => iter.next_back(),
723+
CharIndicesEnum::Full {
724+
iters,
725+
right_chunk_index,
726+
right_byte_offset,
727+
right_byte_offset_for,
728+
..
729+
} => {
730+
if let Some((byte_index, char)) =
731+
iters[*right_chunk_index as usize].next_back()
732+
{
733+
if *right_byte_offset_for != *right_chunk_index {
734+
*right_byte_offset =
735+
*right_byte_offset - byte_index as u32 - char.len_utf8() as u32;
736+
*right_byte_offset_for = *right_chunk_index;
737+
}
738+
Some((byte_index + (*right_byte_offset as usize), char))
739+
} else if *right_chunk_index > 0 {
740+
*right_chunk_index -= 1;
741+
self.next_back()
742+
} else {
743+
None
744+
}
701745
}
702746
}
703747
}
@@ -1168,6 +1212,29 @@ mod tests {
11681212
);
11691213
}
11701214

1215+
#[test]
1216+
fn reverse_char_indices() {
1217+
let mut a = Rope::new();
1218+
a.add("abc");
1219+
a.add("def");
1220+
assert_eq!(
1221+
a.char_indices().rev().collect::<Vec<_>>(),
1222+
"abcdef".char_indices().rev().collect::<Vec<_>>()
1223+
);
1224+
1225+
let mut a = Rope::new();
1226+
a.add("こんにちは");
1227+
assert_eq!(
1228+
a.char_indices().rev().collect::<Vec<_>>(),
1229+
"こんにちは".char_indices().rev().collect::<Vec<_>>()
1230+
);
1231+
a.add("世界");
1232+
assert_eq!(
1233+
a.char_indices().rev().collect::<Vec<_>>(),
1234+
"こんにちは世界".char_indices().rev().collect::<Vec<_>>()
1235+
);
1236+
}
1237+
11711238
#[test]
11721239
fn lines1() {
11731240
let rope = Rope::from("abc");

0 commit comments

Comments
 (0)