Skip to content

Commit fb8e3a6

Browse files
committed
Destructively iterate TreeBuilder fields in TreeBuilder::tree
1 parent 8116f4f commit fb8e3a6

File tree

1 file changed

+30
-19
lines changed

1 file changed

+30
-19
lines changed

crates/vfs/src/tree/builder.rs

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! Build a vfs tree incrementally
66
use std::collections::BTreeMap;
77

8-
use astr::{AStr, CowAStr};
8+
use astr::AStr;
99

1010
use crate::path;
1111
use crate::tree::{Kind, Tree};
@@ -80,43 +80,54 @@ impl<T: BlitFile> TreeBuilder<T> {
8080

8181
/// Generate the final tree by baking all inputs
8282
pub fn tree(self) -> Result<Tree<T>, Error> {
83+
let estimated_capacity = self.implicit_dirs.len() + self.explicit.len();
84+
85+
// Pre-allocate some space to avoid excessive reallocation.
86+
//
87+
// Numbers are chosen such that with the real-world vfs profiled
88+
// locally, we're still a decent bit lower than the size these will
89+
// end up at (so we don't allocate more than we need).
90+
let mut dirs = Vec::with_capacity(self.explicit.len() / 512);
91+
let mut non_dirs = Vec::with_capacity(self.explicit.len() / 4);
92+
for file in self.explicit {
93+
if file.kind.is_directory() {
94+
dirs.push(file);
95+
} else {
96+
non_dirs.push(file);
97+
}
98+
}
99+
83100
// Chain all directories, replace implicits with explicit
84-
let all_dirs = self
85-
.explicit
86-
.iter()
87-
.filter(|f| f.kind.is_directory())
88-
.chain(self.implicit_dirs.values())
89-
.map(|d| (&*d.path, d))
101+
let all_dirs = dirs
102+
.into_iter()
103+
.chain(self.implicit_dirs.into_values())
104+
.map(|d| (d.path.astr(), d))
90105
.collect::<BTreeMap<_, _>>();
91106

92107
// build a set of redirects
93108
let mut redirects = BTreeMap::new();
94109

95110
// Resolve symlinks-to-dirs
96-
for link in &self.explicit {
111+
for link in &non_dirs {
97112
if let Kind::Symlink(target) = &link.kind {
98113
// Resolve the link.
99114
let target = if target.starts_with('/') {
100-
CowAStr::Borrowed(target)
115+
target.clone()
101116
} else if let Some(parent) = link.parent() {
102-
CowAStr::Owned(path::join(parent, target))
117+
path::join(parent, target)
103118
} else {
104-
CowAStr::Borrowed(target)
119+
target.clone()
105120
};
106-
if all_dirs.contains_key(&**target) {
107-
redirects.insert(&*link.path, target);
121+
if all_dirs.contains_key(&target) {
122+
redirects.insert(link.path.astr(), target);
108123
}
109124
}
110125
}
111126

112127
// Insert everything WITHOUT redirects, directory first.
113-
let mut full_set = all_dirs
114-
.into_values()
115-
.chain(self.explicit.iter().filter(|m| !m.kind.is_directory()))
116-
.collect::<Vec<_>>();
128+
let mut full_set = all_dirs.into_values().chain(non_dirs).collect::<Vec<_>>();
117129
full_set.sort_by(|a, b| sorted_paths(a, b));
118130

119-
let estimated_capacity = self.implicit_dirs.len() + self.explicit.len();
120131
let mut tree: Tree<T> = Tree::with_capacity(estimated_capacity);
121132

122133
// Build the initial full tree now.
@@ -131,7 +142,7 @@ impl<T: BlitFile> TreeBuilder<T> {
131142

132143
// Reparent any symlink redirects.
133144
for (source_tree, target_tree) in redirects {
134-
tree.reparent(source_tree, &target_tree)?;
145+
tree.reparent(&source_tree, &target_tree)?;
135146
}
136147
Ok(tree)
137148
}

0 commit comments

Comments
 (0)