Speed up tab searching in TabMap::sync by looking for \t only

Instead of looking for `\n` as a stopping condition, we cap the range
we pass to `SuggestionSnapshot::chunks` to stop on the next line. This
makes character searching faster, because looking for a single character
uses `memchr`. Also, this avoids an extra conditional in a tight loop such
as the chunk scanning one contained in `TabMap::sync`.
This commit is contained in:
Antonio Scandurra 2023-03-30 10:03:13 +02:00
parent 79346b0706
commit af4c4c7cf0

View file

@ -47,7 +47,6 @@ impl TabMap {
new_snapshot.version += 1; new_snapshot.version += 1;
} }
let old_max_offset = old_snapshot.suggestion_snapshot.len();
let mut tab_edits = Vec::with_capacity(suggestion_edits.len()); let mut tab_edits = Vec::with_capacity(suggestion_edits.len());
if old_snapshot.tab_size == new_snapshot.tab_size { if old_snapshot.tab_size == new_snapshot.tab_size {
@ -55,49 +54,46 @@ impl TabMap {
// and any subsequent tabs on that line that moved across the tab expansion // and any subsequent tabs on that line that moved across the tab expansion
// boundary. // boundary.
for suggestion_edit in &mut suggestion_edits { for suggestion_edit in &mut suggestion_edits {
let old_end_column = old_snapshot let old_end = old_snapshot
.suggestion_snapshot .suggestion_snapshot
.to_point(suggestion_edit.old.end) .to_point(suggestion_edit.old.end);
.column(); let old_end_row_successor_offset =
let new_end_column = new_snapshot old_snapshot.suggestion_snapshot.to_offset(cmp::min(
SuggestionPoint::new(old_end.row() + 1, 0),
old_snapshot.suggestion_snapshot.max_point(),
));
let new_end = new_snapshot
.suggestion_snapshot .suggestion_snapshot
.to_point(suggestion_edit.new.end) .to_point(suggestion_edit.new.end);
.column();
let mut offset_from_edit = 0; let mut offset_from_edit = 0;
let mut first_tab_offset = None; let mut first_tab_offset = None;
let mut last_tab_with_changed_expansion_offset = None; let mut last_tab_with_changed_expansion_offset = None;
'outer: for chunk in old_snapshot.suggestion_snapshot.chunks( 'outer: for chunk in old_snapshot.suggestion_snapshot.chunks(
suggestion_edit.old.end..old_max_offset, suggestion_edit.old.end..old_end_row_successor_offset,
false, false,
None, None,
) { ) {
for (ix, mat) in chunk.text.match_indices(&['\t', '\n']) { for (ix, _) in chunk.text.match_indices('\t') {
let offset_from_edit = offset_from_edit + (ix as u32); let offset_from_edit = offset_from_edit + (ix as u32);
match mat { if first_tab_offset.is_none() {
"\t" => { first_tab_offset = Some(offset_from_edit);
if first_tab_offset.is_none() { }
first_tab_offset = Some(offset_from_edit);
}
let old_column = old_end_column + offset_from_edit; let old_column = old_end.column() + offset_from_edit;
let new_column = new_end_column + offset_from_edit; let new_column = new_end.column() + offset_from_edit;
let was_expanded = old_column < old_snapshot.max_expansion_column; let was_expanded = old_column < old_snapshot.max_expansion_column;
let is_expanded = new_column < new_snapshot.max_expansion_column; let is_expanded = new_column < new_snapshot.max_expansion_column;
if was_expanded != is_expanded { if was_expanded != is_expanded {
last_tab_with_changed_expansion_offset = Some(offset_from_edit); last_tab_with_changed_expansion_offset = Some(offset_from_edit);
} else if !was_expanded && !is_expanded { } else if !was_expanded && !is_expanded {
break 'outer; break 'outer;
}
}
"\n" => break 'outer,
_ => unreachable!(),
} }
} }
offset_from_edit += chunk.text.len() as u32; offset_from_edit += chunk.text.len() as u32;
if old_end_column + offset_from_edit >= old_snapshot.max_expansion_column if old_end.column() + offset_from_edit >= old_snapshot.max_expansion_column
&& new_end_column + offset_from_edit >= new_snapshot.max_expansion_column && new_end.column() + offset_from_edit >= new_snapshot.max_expansion_column
{ {
break; break;
} }