Replace some hot TreeMaps with Arc<HashMap> (#49984)
These tend to be very often mutated while we don't really need the subtree sharing of TreeMaps, so replacing them here is generally cheaper. Release Notes: - N/A *or* Added/Fixed/Improved ... Co-authored by: John Tur <jtur@zed.dev>
This commit is contained in:
1 parent
7e3e168761
commit
ca066cbefd
5 files changed
+41
-31
No files matched your search
@@ -113,6 +113,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
use ztracing::instrument;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
borrow::Cow,
|
||||
@@ -175,9 +176,9 @@ pub trait ToDisplayPoint {
|
||||
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint;
|
||||
}
|
||||
|
||||
type TextHighlights = TreeMap<HighlightKey, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>;
|
||||
type TextHighlights = Arc<HashMap<HighlightKey, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>>;
|
||||
type SemanticTokensHighlights =
|
||||
TreeMap<BufferId, (Arc<[SemanticTokenHighlight]>, Arc<HighlightStyleInterner>)>;
|
||||
Arc<HashMap<BufferId, (Arc<[SemanticTokenHighlight]>, Arc<HighlightStyleInterner>)>>;
|
||||
type InlayHighlights = TreeMap<HighlightKey, TreeMap<InlayId, (HighlightStyle, InlayHighlight)>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -478,7 +479,7 @@ impl DisplayMap {
|
||||
diagnostics_max_severity,
|
||||
text_highlights: Default::default(),
|
||||
inlay_highlights: Default::default(),
|
||||
semantic_token_highlights: TreeMap::default(),
|
||||
semantic_token_highlights: Default::default(),
|
||||
clip_at_line_ends: false,
|
||||
masked: false,
|
||||
companion: None,
|
||||
@@ -1226,22 +1227,25 @@ impl DisplayMap {
|
||||
cx: &App,
|
||||
) {
|
||||
let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let to_insert = match self.text_highlights.remove(&key) {
|
||||
Some(mut previous) if merge => match Arc::get_mut(&mut previous) {
|
||||
Some((_, previous_ranges)) => {
|
||||
match Arc::make_mut(&mut self.text_highlights).entry(key) {
|
||||
Entry::Occupied(mut slot) => match Arc::get_mut(slot.get_mut()) {
|
||||
Some((_, previous_ranges)) if merge => {
|
||||
previous_ranges.extend(ranges);
|
||||
previous_ranges.sort_by(|a, b| a.start.cmp(&b.start, &multi_buffer_snapshot));
|
||||
previous
|
||||
}
|
||||
None => Arc::new((style, {
|
||||
ranges.extend(previous.1.iter().cloned());
|
||||
Some((previous_style, previous_ranges)) => {
|
||||
*previous_style = style;
|
||||
*previous_ranges = ranges;
|
||||
}
|
||||
None if merge => {
|
||||
ranges.extend(slot.get().1.iter().cloned());
|
||||
ranges.sort_by(|a, b| a.start.cmp(&b.start, &multi_buffer_snapshot));
|
||||
ranges
|
||||
})),
|
||||
slot.insert(Arc::new((style, ranges)));
|
||||
}
|
||||
None => _ = slot.insert(Arc::new((style, ranges))),
|
||||
},
|
||||
_ => Arc::new((style, ranges)),
|
||||
};
|
||||
self.text_highlights.insert(key, to_insert);
|
||||
Entry::Vacant(slot) => _ = slot.insert(Arc::new((style, ranges))),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@@ -1288,14 +1292,16 @@ impl DisplayMap {
|
||||
}
|
||||
|
||||
pub fn clear_highlights(&mut self, key: HighlightKey) -> bool {
|
||||
let mut cleared = self.text_highlights.remove(&key).is_some();
|
||||
let mut cleared = Arc::make_mut(&mut self.text_highlights)
|
||||
.remove(&key)
|
||||
.is_some();
|
||||
cleared |= self.inlay_highlights.remove(&key).is_some();
|
||||
cleared
|
||||
}
|
||||
|
||||
pub fn clear_highlights_with(&mut self, f: &mut dyn FnMut(&HighlightKey) -> bool) -> bool {
|
||||
let mut cleared = false;
|
||||
self.text_highlights.retain(|k, _| {
|
||||
Arc::make_mut(&mut self.text_highlights).retain(|k, _| {
|
||||
let b = !f(k);
|
||||
cleared |= b;
|
||||
b
|
||||
@@ -1448,7 +1454,7 @@ impl DisplayMap {
|
||||
}
|
||||
|
||||
pub fn invalidate_semantic_highlights(&mut self, buffer_id: BufferId) {
|
||||
self.semantic_token_highlights.remove(&buffer_id);
|
||||
Arc::make_mut(&mut self.semantic_token_highlights).remove(&buffer_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1328,9 +1328,10 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
MultiBuffer,
|
||||
display_map::{HighlightKey, InlayHighlights, TextHighlights},
|
||||
display_map::{HighlightKey, InlayHighlights},
|
||||
hover_links::InlayHighlight,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use gpui::{App, HighlightStyle};
|
||||
use multi_buffer::Anchor;
|
||||
use project::{InlayHint, InlayHintLabel, ResolveState};
|
||||
@@ -1897,7 +1898,7 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
let mut text_highlights = TextHighlights::default();
|
||||
let mut text_highlights = HashMap::default();
|
||||
let text_highlight_count = rng.random_range(0_usize..10);
|
||||
let mut text_highlight_ranges = (0..text_highlight_count)
|
||||
.map(|_| buffer_snapshot.random_byte_range(MultiBufferOffset(0), &mut rng))
|
||||
@@ -1917,6 +1918,7 @@ mod tests {
|
||||
.collect(),
|
||||
)),
|
||||
);
|
||||
let text_highlights = Arc::new(text_highlights);
|
||||
|
||||
let mut inlay_highlights = InlayHighlights::default();
|
||||
if !inlays.is_empty() {
|
||||
|
||||
@@ -122,7 +122,10 @@ impl Editor {
|
||||
if !self.mode().is_full() || !self.semantic_token_state.enabled() {
|
||||
self.invalidate_semantic_tokens(None);
|
||||
self.display_map.update(cx, |display_map, _| {
|
||||
display_map.semantic_token_highlights.clear();
|
||||
match Arc::get_mut(&mut display_map.semantic_token_highlights) {
|
||||
Some(highlights) => highlights.clear(),
|
||||
None => display_map.semantic_token_highlights = Arc::new(Default::default()),
|
||||
};
|
||||
});
|
||||
self.semantic_token_state.update_task = Task::ready(());
|
||||
cx.notify();
|
||||
@@ -171,8 +174,8 @@ impl Editor {
|
||||
.display_map
|
||||
.read(cx)
|
||||
.semantic_token_highlights
|
||||
.iter()
|
||||
.map(|(buffer_id, _)| *buffer_id)
|
||||
.keys()
|
||||
.copied()
|
||||
.filter(|buffer_id| !buffers_to_query.contains_key(buffer_id))
|
||||
.filter(|buffer_id| {
|
||||
!self
|
||||
@@ -308,7 +311,7 @@ impl Editor {
|
||||
token_highlights.sort_by(|a, b| {
|
||||
a.range.start.cmp(&b.range.start, &multi_buffer_snapshot)
|
||||
});
|
||||
display_map.semantic_token_highlights.insert(
|
||||
Arc::make_mut(&mut display_map.semantic_token_highlights).insert(
|
||||
buffer_id,
|
||||
(Arc::from(token_highlights), Arc::new(interner)),
|
||||
);
|
||||
|
||||
@@ -624,7 +624,7 @@ pub struct MultiBufferSnapshot {
|
||||
diffs: TreeMap<BufferId, DiffStateSnapshot>,
|
||||
diff_transforms: SumTree<DiffTransform>,
|
||||
excerpt_ids: SumTree<ExcerptIdMapping>,
|
||||
replaced_excerpts: TreeMap<ExcerptId, ExcerptId>,
|
||||
replaced_excerpts: Arc<HashMap<ExcerptId, ExcerptId>>,
|
||||
non_text_state_update_count: usize,
|
||||
edit_count: usize,
|
||||
is_dirty: bool,
|
||||
@@ -1967,7 +1967,10 @@ impl MultiBuffer {
|
||||
*has_deleted_file = false;
|
||||
*has_conflict = false;
|
||||
*has_inverted_diff = false;
|
||||
replaced_excerpts.clear();
|
||||
match Arc::get_mut(replaced_excerpts) {
|
||||
Some(replaced_excerpts) => replaced_excerpts.clear(),
|
||||
None => *replaced_excerpts = Default::default(),
|
||||
}
|
||||
|
||||
let edits = Self::sync_diff_transforms(
|
||||
self.snapshot.get_mut(),
|
||||
|
||||
@@ -382,9 +382,7 @@ impl MultiBuffer {
|
||||
{
|
||||
last.context.end = last.context.end.max(existing_range.end);
|
||||
to_remove.push(*existing_id);
|
||||
self.snapshot
|
||||
.get_mut()
|
||||
.replaced_excerpts
|
||||
Arc::make_mut(&mut self.snapshot.get_mut().replaced_excerpts)
|
||||
.insert(*existing_id, *last_id);
|
||||
existing_iter.next();
|
||||
continue;
|
||||
@@ -462,9 +460,7 @@ impl MultiBuffer {
|
||||
(Some(_), Some((_, existing_range))) => {
|
||||
let existing_id = existing_iter.next().unwrap();
|
||||
let new_id = next_excerpt_id();
|
||||
self.snapshot
|
||||
.get_mut()
|
||||
.replaced_excerpts
|
||||
Arc::make_mut(&mut self.snapshot.get_mut().replaced_excerpts)
|
||||
.insert(existing_id, new_id);
|
||||
to_remove.push(existing_id);
|
||||
let mut range = new_iter.next().unwrap();
|
||||
|
||||
Reference in new issue
Block a user