##// END OF EJS Templates
dirstate-tree: Refactor DirstateMap::drop_file to be recursive...
Simon Sapin -
r47963:1249eb9c default
parent child Browse files
Show More
@@ -153,19 +153,6 b" impl<'on_disk> DirstateMap<'on_disk> {"
153 root: &'tree mut ChildNodes<'on_disk>,
153 root: &'tree mut ChildNodes<'on_disk>,
154 path: &HgPath,
154 path: &HgPath,
155 ) -> Option<&'tree mut Node<'on_disk>> {
155 ) -> Option<&'tree mut Node<'on_disk>> {
156 Self::get_node_mut_tracing_ancestors(root, path, |_| {})
157 }
158
159 /// Same as `get_node_mut`, and calls `each_ancestor` for each ancestor of
160 /// the node.
161 ///
162 /// Note that `each_ancestor` may be called (with what would be ancestors)
163 /// even if it turns out there is no node at `path`.
164 fn get_node_mut_tracing_ancestors<'tree>(
165 root: &'tree mut ChildNodes<'on_disk>,
166 path: &HgPath,
167 mut each_ancestor: impl FnMut(&mut Node),
168 ) -> Option<&'tree mut Node<'on_disk>> {
169 let mut children = root;
156 let mut children = root;
170 let mut components = path.components();
157 let mut components = path.components();
171 let mut component =
158 let mut component =
@@ -173,7 +160,6 b" impl<'on_disk> DirstateMap<'on_disk> {"
173 loop {
160 loop {
174 let child = children.get_mut(component)?;
161 let child = children.get_mut(component)?;
175 if let Some(next_component) = components.next() {
162 if let Some(next_component) = components.next() {
176 each_ancestor(child);
177 component = next_component;
163 component = next_component;
178 children = &mut child.children;
164 children = &mut child.children;
179 } else {
165 } else {
@@ -369,34 +355,47 b" impl<'on_disk> super::dispatch::Dirstate"
369 filename: &HgPath,
355 filename: &HgPath,
370 old_state: EntryState,
356 old_state: EntryState,
371 ) -> Result<bool, DirstateMapError> {
357 ) -> Result<bool, DirstateMapError> {
372 let was_tracked = old_state.is_tracked();
358 struct Dropped {
373 if let Some(node) = Self::get_node_mut_tracing_ancestors(
359 was_tracked: bool,
374 &mut self.root,
360 had_entry: bool,
375 filename,
361 had_copy_source: bool,
376 |ancestor| {
362 }
377 if was_tracked {
363 fn recur(nodes: &mut ChildNodes, path: &HgPath) -> Option<Dropped> {
378 ancestor.tracked_descendants_count -= 1
364 let (first_path_component, rest_of_path) =
365 path.split_first_component();
366 let node = nodes.get_mut(first_path_component)?;
367 let dropped;
368 if let Some(rest) = rest_of_path {
369 dropped = recur(&mut node.children, rest)?;
370 if dropped.was_tracked {
371 node.tracked_descendants_count -= 1;
379 }
372 }
380 },
373 } else {
381 ) {
374 dropped = Dropped {
382 let had_entry = node.entry.is_some();
375 was_tracked: node
383 let had_copy_source = node.copy_source.is_some();
376 .entry
377 .as_ref()
378 .map_or(false, |entry| entry.state.is_tracked()),
379 had_entry: node.entry.take().is_some(),
380 had_copy_source: node.copy_source.take().is_some(),
381 };
382 // TODO: this leaves in the tree a "non-file" node. Should we
383 // remove the node instead, together with ancestor nodes for
384 // directories that become empty?
385 }
386 Some(dropped)
387 }
384
388
385 // TODO: this leaves in the tree a "non-file" node. Should we
389 if let Some(dropped) = recur(&mut self.root, filename) {
386 // remove the node instead, together with ancestor nodes for
390 if dropped.had_entry {
387 // directories that become empty?
388 node.entry = None;
389 node.copy_source = None;
390
391 if had_entry {
392 self.nodes_with_entry_count -= 1
391 self.nodes_with_entry_count -= 1
393 }
392 }
394 if had_copy_source {
393 if dropped.had_copy_source {
395 self.nodes_with_copy_source_count -= 1
394 self.nodes_with_copy_source_count -= 1
396 }
395 }
397 Ok(had_entry)
396 Ok(dropped.had_entry)
398 } else {
397 } else {
399 assert!(!was_tracked);
398 debug_assert!(!old_state.is_tracked());
400 Ok(false)
399 Ok(false)
401 }
400 }
402 }
401 }
@@ -5,6 +5,7 b''
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::utils::SliceExt;
8 use std::borrow::Borrow;
9 use std::borrow::Borrow;
9 use std::borrow::Cow;
10 use std::borrow::Cow;
10 use std::convert::TryFrom;
11 use std::convert::TryFrom;
@@ -232,6 +233,15 b' impl HgPath {'
232 self.inner.split(|&byte| byte == b'/').map(HgPath::new)
233 self.inner.split(|&byte| byte == b'/').map(HgPath::new)
233 }
234 }
234
235
236 /// Returns the first (that is "root-most") slash-separated component of
237 /// the path, and the rest after the first slash if there is one.
238 pub fn split_first_component(&self) -> (&HgPath, Option<&HgPath>) {
239 match self.inner.split_2(b'/') {
240 Some((a, b)) => (HgPath::new(a), Some(HgPath::new(b))),
241 None => (self, None),
242 }
243 }
244
235 pub fn parent(&self) -> &Self {
245 pub fn parent(&self) -> &Self {
236 let inner = self.as_bytes();
246 let inner = self.as_bytes();
237 HgPath::new(match inner.iter().rposition(|b| *b == b'/') {
247 HgPath::new(match inner.iter().rposition(|b| *b == b'/') {
General Comments 0
You need to be logged in to leave comments. Login now