fix: review follow-ups for #5 and the Swift lexical preview #8
1 changed files with 24 additions and 13 deletions
perf(scan): index import edges once instead of scanning per file
imported_paths found the file node with a linear scan of all nodes and then filtered all edges, for every Python/Dart file it built a set for: O(files x (nodes + edges)) during resolution, about 10^10 comparisons for 10k files and a million edges. Imports edges are now indexed by source file on first use and the file node is looked up by its stable id, as resolve_import already does. The index is complete when first built: resolve_relationships resolves every import before any call. Output is unchanged (all 124 tests pass).
commit
3fbb9275a5
37
src/scan.rs
37
src/scan.rs
|
|
@ -248,6 +248,9 @@ struct ScanState {
|
|||
references: HashMap<String, HashSet<String>>,
|
||||
/// Lexical-language file -> repository files it imports (resolved edges).
|
||||
imported_paths: HashMap<String, Rc<HashSet<String>>>,
|
||||
/// Imports edges by source file id, built once on first use: scanning every
|
||||
/// node and edge per file made resolution O(files x (nodes + edges)).
|
||||
imports_by_file: Option<HashMap<String, Vec<String>>>,
|
||||
/// `name:` of the root pubspec.yaml, so `package:<name>/x.dart` maps to lib/x.dart.
|
||||
dart_package: Option<String>,
|
||||
}
|
||||
|
|
@ -283,6 +286,7 @@ impl ScanState {
|
|||
rust: RustIndex::default(),
|
||||
references: HashMap::new(),
|
||||
imported_paths: HashMap::new(),
|
||||
imports_by_file: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1319,20 +1323,27 @@ impl ScanState {
|
|||
if let Some(found) = self.imported_paths.get(path) {
|
||||
return Rc::clone(found);
|
||||
}
|
||||
if self.imports_by_file.is_none() {
|
||||
let mut index: HashMap<String, Vec<String>> = HashMap::new();
|
||||
for edge in self.edges.iter().filter(|e| e.kind == EdgeKind::Imports) {
|
||||
index
|
||||
.entry(edge.source.clone())
|
||||
.or_default()
|
||||
.push(edge.target.clone());
|
||||
}
|
||||
self.imports_by_file = Some(index);
|
||||
}
|
||||
let file_id = stable_id("file", path);
|
||||
let paths: HashSet<String> = self
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|n| n.kind == NodeKind::File && n.path.as_deref() == Some(path))
|
||||
.map(|file| {
|
||||
self.edges
|
||||
.iter()
|
||||
.filter(|e| e.kind == EdgeKind::Imports && e.source == file.id)
|
||||
.filter_map(|e| self.node(&e.target))
|
||||
.filter(|n| n.kind == NodeKind::File)
|
||||
.filter_map(|n| n.path.clone())
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
.imports_by_file
|
||||
.as_ref()
|
||||
.and_then(|index| index.get(&file_id))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|target| self.node(target))
|
||||
.filter(|n| n.kind == NodeKind::File)
|
||||
.filter_map(|n| n.path.clone())
|
||||
.collect();
|
||||
let paths = Rc::new(paths);
|
||||
self.imported_paths
|
||||
.insert(path.to_owned(), Rc::clone(&paths));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue