55//! Build a vfs tree incrementally
66use std:: collections:: BTreeMap ;
77
8- use astr:: { AStr , CowAStr } ;
8+ use astr:: AStr ;
99
1010use crate :: path;
1111use 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