Switch worktree entries to HashMap

This commit is contained in:
Nathan Sobo 2021-04-08 15:56:57 -06:00 committed by Nathan Sobo
parent 3803eb85a5
commit cdfd61369e

View file

@ -33,7 +33,7 @@ pub struct Worktree(Arc<RwLock<WorktreeState>>);
struct WorktreeState { struct WorktreeState {
id: usize, id: usize,
path: PathBuf, path: PathBuf,
entries: Vec<Entry>, entries: HashMap<usize, Entry>,
file_paths: Vec<PathEntry>, file_paths: Vec<PathEntry>,
histories: HashMap<usize, History>, histories: HashMap<usize, History>,
scanning: bool, scanning: bool,
@ -55,7 +55,7 @@ impl Worktree {
let tree = Self(Arc::new(RwLock::new(WorktreeState { let tree = Self(Arc::new(RwLock::new(WorktreeState {
id, id,
path: path.into(), path: path.into(),
entries: Vec::new(), entries: HashMap::new(),
file_paths: Vec::new(), file_paths: Vec::new(),
histories: HashMap::new(), histories: HashMap::new(),
scanning: ctx.is_some(), scanning: ctx.is_some(),
@ -102,7 +102,7 @@ impl Worktree {
if metadata.file_type().is_dir() { if metadata.file_type().is_dir() {
let is_ignored = is_ignored || name == ".git"; let is_ignored = is_ignored || name == ".git";
let id = self.push_dir(None, name, ino, is_symlink, is_ignored); let id = self.insert_dir(None, name, ino, is_symlink, is_ignored);
let (tx, rx) = channel::unbounded(); let (tx, rx) = channel::unbounded();
tx.send(Ok(DirToScan { tx.send(Ok(DirToScan {
@ -110,7 +110,6 @@ impl Worktree {
path, path,
relative_path, relative_path,
ignore: Some(ignore), ignore: Some(ignore),
dirs_to_scan: tx_,
dirs_to_scan: tx.clone(), dirs_to_scan: tx.clone(),
})) }))
.unwrap(); .unwrap();
@ -127,7 +126,7 @@ impl Worktree {
.into_iter() .into_iter()
.collect::<io::Result<()>>()?; .collect::<io::Result<()>>()?;
} else { } else {
self.push_file(None, name, ino, is_symlink, is_ignored, relative_path); self.insert_file(None, name, ino, is_symlink, is_ignored, relative_path);
} }
Ok(()) Ok(())
@ -157,7 +156,7 @@ impl Worktree {
} }
} }
let id = self.push_dir(Some(to_scan.id), name, ino, is_symlink, is_ignored); let id = self.insert_dir(Some(to_scan.id), name, ino, is_symlink, is_ignored);
new_children.push(id); new_children.push(id);
let dirs_to_scan = to_scan.dirs_to_scan.clone(); let dirs_to_scan = to_scan.dirs_to_scan.clone();
@ -173,7 +172,7 @@ impl Worktree {
i.matched(to_scan.path.join(&name), false).is_ignore() i.matched(to_scan.path.join(&name), false).is_ignore()
}); });
new_children.push(self.push_file( new_children.push(self.insert_file(
Some(to_scan.id), Some(to_scan.id),
name, name,
ino, ino,
@ -184,14 +183,15 @@ impl Worktree {
}; };
} }
if let Entry::Dir { children, .. } = &mut self.0.write().entries[to_scan.id] { if let Some(Entry::Dir { children, .. }) = &mut self.0.write().entries.get_mut(&to_scan.id)
{
*children = new_children.clone(); *children = new_children.clone();
} }
Ok(()) Ok(())
} }
fn push_dir( fn insert_dir(
&self, &self,
parent: Option<usize>, parent: Option<usize>,
name: OsString, name: OsString,
@ -201,18 +201,21 @@ impl Worktree {
) -> usize { ) -> usize {
let entries = &mut self.0.write().entries; let entries = &mut self.0.write().entries;
let dir_id = entries.len(); let dir_id = entries.len();
entries.push(Entry::Dir { entries.insert(
parent, dir_id,
name, Entry::Dir {
ino, parent,
is_symlink, name,
is_ignored, ino,
children: Vec::new(), is_symlink,
}); is_ignored,
children: Vec::new(),
},
);
dir_id dir_id
} }
fn push_file( fn insert_file(
&self, &self,
parent: Option<usize>, parent: Option<usize>,
name: OsString, name: OsString,
@ -228,13 +231,16 @@ impl Worktree {
let mut state = self.0.write(); let mut state = self.0.write();
let entry_id = state.entries.len(); let entry_id = state.entries.len();
state.entries.push(Entry::File { state.entries.insert(
parent, entry_id,
name, Entry::File {
ino, parent,
is_symlink, name,
is_ignored, ino,
}); is_symlink,
is_ignored,
},
);
state.file_paths.push(PathEntry { state.file_paths.push(PathEntry {
entry_id, entry_id,
path_chars, path_chars,
@ -254,7 +260,7 @@ impl Worktree {
let mut entries = Vec::new(); let mut entries = Vec::new();
loop { loop {
let entry = &state.entries[entry_id]; let entry = &state.entries[&entry_id];
entries.push(entry); entries.push(entry);
if let Some(parent_id) = entry.parent() { if let Some(parent_id) = entry.parent() {
entry_id = parent_id; entry_id = parent_id;
@ -277,7 +283,7 @@ impl Worktree {
} }
fn fmt_entry(&self, f: &mut fmt::Formatter<'_>, entry_id: usize, indent: usize) -> fmt::Result { fn fmt_entry(&self, f: &mut fmt::Formatter<'_>, entry_id: usize, indent: usize) -> fmt::Result {
match &self.0.read().entries[entry_id] { match &self.0.read().entries[&entry_id] {
Entry::Dir { name, children, .. } => { Entry::Dir { name, children, .. } => {
write!( write!(
f, f,
@ -498,7 +504,7 @@ impl Iterator for Iter {
if !self.started { if !self.started {
self.started = true; self.started = true;
return if let Some(entry) = state.entries.first().cloned() { return if let Some(entry) = state.entries.get(&0).cloned() {
self.stack.push(IterStackEntry { self.stack.push(IterStackEntry {
entry_id: 0, entry_id: 0,
child_idx: 0, child_idx: 0,
@ -511,7 +517,7 @@ impl Iterator for Iter {
} }
while let Some(parent) = self.stack.last_mut() { while let Some(parent) = self.stack.last_mut() {
if let Entry::Dir { children, .. } = &state.entries[parent.entry_id] { if let Entry::Dir { children, .. } = &state.entries[&parent.entry_id] {
if parent.child_idx < children.len() { if parent.child_idx < children.len() {
let child_id = children[post_inc(&mut parent.child_idx)]; let child_id = children[post_inc(&mut parent.child_idx)];
@ -522,7 +528,7 @@ impl Iterator for Iter {
return Some(Traversal::Push { return Some(Traversal::Push {
entry_id: child_id, entry_id: child_id,
entry: state.entries[child_id].clone(), entry: state.entries[&child_id].clone(),
}); });
} else { } else {
self.stack.pop(); self.stack.pop();
@ -614,7 +620,7 @@ pub fn match_paths(
.iter() .iter()
.map(|tree| { .map(|tree| {
let skip_prefix = if trees.len() == 1 { let skip_prefix = if trees.len() == 1 {
if let Some(Entry::Dir { name, .. }) = tree.entries.get(0) { if let Some(Entry::Dir { name, .. }) = tree.entries.get(&0) {
let name = name.to_string_lossy(); let name = name.to_string_lossy();
if name == "/" { if name == "/" {
1 1