mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
feat: make hightlighting linear
In https://youtu.be/qvIZZf5dmTE, we've noticed that AstIdMap does a linear lookup when going from SyntaxNode to Id. This leads to accidentally quadratic overall performance. Replace linear lookup with a O(1) hashmap lookup. Future work: don't duplicate `SyntaxNodePtr` in `AstIdMap` and switch to "call site dependency injection" style storage (eg, store a `HashSet<ErasedFileAstId>`). See the explanation of the work here on YouTube https://youtu.be/wvEgymUm7cY :-)
This commit is contained in:
parent
b519a179b4
commit
c603b9043f
1 changed files with 8 additions and 5 deletions
|
@ -14,6 +14,7 @@ use std::{
|
||||||
|
|
||||||
use la_arena::{Arena, Idx};
|
use la_arena::{Arena, Idx};
|
||||||
use profile::Count;
|
use profile::Count;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
|
use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
|
||||||
|
|
||||||
/// `AstId` points to an AST node in a specific file.
|
/// `AstId` points to an AST node in a specific file.
|
||||||
|
@ -63,6 +64,7 @@ type ErasedFileAstId = Idx<SyntaxNodePtr>;
|
||||||
#[derive(Debug, PartialEq, Eq, Default)]
|
#[derive(Debug, PartialEq, Eq, Default)]
|
||||||
pub struct AstIdMap {
|
pub struct AstIdMap {
|
||||||
arena: Arena<SyntaxNodePtr>,
|
arena: Arena<SyntaxNodePtr>,
|
||||||
|
map: FxHashMap<SyntaxNodePtr, ErasedFileAstId>,
|
||||||
_c: Count<Self>,
|
_c: Count<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +91,7 @@ impl AstIdMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
res.map.extend(res.arena.iter().map(|(idx, ptr)| (ptr.clone(), idx)));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,16 +99,16 @@ impl AstIdMap {
|
||||||
let raw = self.erased_ast_id(item.syntax());
|
let raw = self.erased_ast_id(item.syntax());
|
||||||
FileAstId { raw, _ty: PhantomData }
|
FileAstId { raw, _ty: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
|
fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
|
||||||
let ptr = SyntaxNodePtr::new(item);
|
let ptr = SyntaxNodePtr::new(item);
|
||||||
match self.arena.iter().find(|(_id, i)| **i == ptr) {
|
*self.map.get(&ptr).unwrap_or_else(|| {
|
||||||
Some((it, _)) => it,
|
panic!(
|
||||||
None => panic!(
|
|
||||||
"Can't find {:?} in AstIdMap:\n{:?}",
|
"Can't find {:?} in AstIdMap:\n{:?}",
|
||||||
item,
|
item,
|
||||||
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
|
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
|
||||||
),
|
)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
|
pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
|
||||||
|
|
Loading…
Reference in a new issue