Avoid duplicating VfsPath in vfs::path_interner::PathInterner by using an IndexSet

This commit is contained in:
Alexandru Macovei 2021-04-01 14:01:59 +03:00
parent 32304d14a1
commit 4e2a6ac7ea
3 changed files with 18 additions and 13 deletions

1
Cargo.lock generated
View file

@ -1867,6 +1867,7 @@ name = "vfs"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"fst", "fst",
"indexmap",
"paths", "paths",
"rustc-hash", "rustc-hash",
] ]

View file

@ -14,3 +14,4 @@ rustc-hash = "1.0"
fst = "0.4" fst = "0.4"
paths = { path = "../paths", version = "0.0.0" } paths = { path = "../paths", version = "0.0.0" }
indexmap = "1.6.2"

View file

@ -1,15 +1,22 @@
//! Maps paths to compact integer ids. We don't care about clearings paths which //! 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 //! no longer exist -- the assumption is total size of paths we ever look at is
//! not too big. //! not too big.
use rustc_hash::FxHashMap; use std::hash::BuildHasherDefault;
use indexmap::IndexSet;
use rustc_hash::FxHasher;
use crate::{FileId, VfsPath}; use crate::{FileId, VfsPath};
/// Structure to map between [`VfsPath`] and [`FileId`]. /// Structure to map between [`VfsPath`] and [`FileId`].
#[derive(Default)]
pub(crate) struct PathInterner { pub(crate) struct PathInterner {
map: FxHashMap<VfsPath, FileId>, map: IndexSet<VfsPath, BuildHasherDefault<FxHasher>>,
vec: Vec<VfsPath>, }
impl Default for PathInterner {
fn default() -> Self {
Self { map: IndexSet::default() }
}
} }
impl PathInterner { impl PathInterner {
@ -17,7 +24,7 @@ impl PathInterner {
/// ///
/// If `path` does not exists in `self`, returns [`None`]. /// If `path` does not exists in `self`, returns [`None`].
pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> { pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> {
self.map.get(path).copied() self.map.get_index_of(path).map(|i| FileId(i as u32))
} }
/// Insert `path` in `self`. /// Insert `path` in `self`.
@ -25,13 +32,9 @@ impl PathInterner {
/// - If `path` already exists in `self`, returns its associated id; /// - If `path` already exists in `self`, returns its associated id;
/// - Else, returns a newly allocated id. /// - Else, returns a newly allocated id.
pub(crate) fn intern(&mut self, path: VfsPath) -> FileId { pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
if let Some(id) = self.get(&path) { let (id, _added) = self.map.insert_full(path);
return id; assert!(id < u32::MAX as usize);
} FileId(id as u32)
let id = FileId(self.vec.len() as u32);
self.map.insert(path.clone(), id);
self.vec.push(path);
id
} }
/// Returns the path corresponding to `id`. /// Returns the path corresponding to `id`.
@ -40,6 +43,6 @@ impl PathInterner {
/// ///
/// Panics if `id` does not exists in `self`. /// Panics if `id` does not exists in `self`.
pub(crate) fn lookup(&self, id: FileId) -> &VfsPath { pub(crate) fn lookup(&self, id: FileId) -> &VfsPath {
&self.vec[id.0 as usize] self.map.get_index(id.0 as usize).unwrap()
} }
} }