summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/vfs/src/path_interner.rs')
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/path_interner.rs48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs b/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs
new file mode 100644
index 000000000..6e049f0d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs
@@ -0,0 +1,48 @@
+//! Maps paths to compact integer ids. We don't care about clearings paths which
+//! no longer exist -- the assumption is total size of paths we ever look at is
+//! not too big.
+use std::hash::BuildHasherDefault;
+
+use indexmap::IndexSet;
+use rustc_hash::FxHasher;
+
+use crate::{FileId, VfsPath};
+
+/// Structure to map between [`VfsPath`] and [`FileId`].
+pub(crate) struct PathInterner {
+ map: IndexSet<VfsPath, BuildHasherDefault<FxHasher>>,
+}
+
+impl Default for PathInterner {
+ fn default() -> Self {
+ Self { map: IndexSet::default() }
+ }
+}
+
+impl PathInterner {
+ /// Get the id corresponding to `path`.
+ ///
+ /// If `path` does not exists in `self`, returns [`None`].
+ pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> {
+ self.map.get_index_of(path).map(|i| FileId(i as u32))
+ }
+
+ /// Insert `path` in `self`.
+ ///
+ /// - If `path` already exists in `self`, returns its associated id;
+ /// - Else, returns a newly allocated id.
+ pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
+ let (id, _added) = self.map.insert_full(path);
+ assert!(id < u32::MAX as usize);
+ FileId(id as u32)
+ }
+
+ /// Returns the path corresponding to `id`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `id` does not exists in `self`.
+ pub(crate) fn lookup(&self, id: FileId) -> &VfsPath {
+ self.map.get_index(id.0 as usize).unwrap()
+ }
+}