##// END OF EJS Templates
dirstate-tree: Fold "tracked descendants" counter update in main walk...
Simon Sapin -
r47890:7109a388 default
parent child Browse files
Show More
@@ -1,653 +1,647 b''
1 1 use bytes_cast::BytesCast;
2 2 use micro_timer::timed;
3 3 use std::convert::TryInto;
4 4 use std::path::PathBuf;
5 5
6 6 use super::path_with_basename::WithBasename;
7 7 use crate::dirstate::parsers::clear_ambiguous_mtime;
8 8 use crate::dirstate::parsers::pack_entry;
9 9 use crate::dirstate::parsers::packed_entry_size;
10 10 use crate::dirstate::parsers::parse_dirstate_entries;
11 11 use crate::dirstate::parsers::parse_dirstate_parents;
12 12 use crate::dirstate::parsers::Timestamp;
13 13 use crate::matchers::Matcher;
14 14 use crate::revlog::node::NULL_NODE;
15 15 use crate::utils::hg_path::{HgPath, HgPathBuf};
16 16 use crate::CopyMapIter;
17 17 use crate::DirstateEntry;
18 18 use crate::DirstateError;
19 19 use crate::DirstateMapError;
20 20 use crate::DirstateParents;
21 21 use crate::DirstateStatus;
22 22 use crate::EntryState;
23 23 use crate::FastHashMap;
24 24 use crate::PatternFileWarning;
25 25 use crate::StateMapIter;
26 26 use crate::StatusError;
27 27 use crate::StatusOptions;
28 28
29 29 pub struct DirstateMap {
30 30 parents: Option<DirstateParents>,
31 31 dirty_parents: bool,
32 32 pub(super) root: ChildNodes,
33 33
34 34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
35 35 nodes_with_entry_count: usize,
36 36
37 37 /// Number of nodes anywhere in the tree that have
38 38 /// `.copy_source.is_some()`.
39 39 nodes_with_copy_source_count: usize,
40 40 }
41 41
42 42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
43 43 /// map key would also work: all paths in a given map have the same parent
44 44 /// path, so comparing full paths gives the same result as comparing base
45 45 /// names. However `BTreeMap` would waste time always re-comparing the same
46 46 /// string prefix.
47 47 pub(super) type ChildNodes = FastHashMap<WithBasename<HgPathBuf>, Node>;
48 48
49 49 /// Represents a file or a directory
50 50 #[derive(Default)]
51 51 pub(super) struct Node {
52 52 /// `None` for directories
53 53 pub(super) entry: Option<DirstateEntry>,
54 54
55 55 pub(super) copy_source: Option<HgPathBuf>,
56 56
57 57 pub(super) children: ChildNodes,
58 58
59 59 /// How many (non-inclusive) descendants of this node are tracked files
60 60 tracked_descendants_count: usize,
61 61 }
62 62
63 63 impl Node {
64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
65 fn is_tracked_file(&self) -> bool {
66 if let Some(entry) = &self.entry {
67 entry.state.is_tracked()
68 } else {
69 false
70 }
71 }
72
73 64 pub(super) fn state(&self) -> Option<EntryState> {
74 65 self.entry.as_ref().map(|entry| entry.state)
75 66 }
76 67 }
77 68
78 69 /// `(full_path, entry, copy_source)`
79 70 type NodeDataMut<'a> = (
80 71 &'a WithBasename<HgPathBuf>,
81 72 &'a mut Option<DirstateEntry>,
82 73 &'a mut Option<HgPathBuf>,
83 74 );
84 75
85 76 impl DirstateMap {
86 77 pub fn new() -> Self {
87 78 Self {
88 79 parents: None,
89 80 dirty_parents: false,
90 81 root: ChildNodes::default(),
91 82 nodes_with_entry_count: 0,
92 83 nodes_with_copy_source_count: 0,
93 84 }
94 85 }
95 86
96 87 fn get_node(&self, path: &HgPath) -> Option<&Node> {
97 88 let mut children = &self.root;
98 89 let mut components = path.components();
99 90 let mut component =
100 91 components.next().expect("expected at least one components");
101 92 loop {
102 93 let child = children.get(component)?;
103 94 if let Some(next_component) = components.next() {
104 95 component = next_component;
105 96 children = &child.children;
106 97 } else {
107 98 return Some(child);
108 99 }
109 100 }
110 101 }
111 102
112 103 /// Returns a mutable reference to the node at `path` if it exists
113 104 ///
114 105 /// This takes `root` instead of `&mut self` so that callers can mutate
115 106 /// other fields while the returned borrow is still valid
116 107 fn get_node_mut<'tree>(
117 108 root: &'tree mut ChildNodes,
118 109 path: &HgPath,
119 110 ) -> Option<&'tree mut Node> {
120 Self::each_and_get(root, path, |_| {})
111 Self::get_node_mut_tracing_ancestors(root, path, |_| {})
121 112 }
122 113
123 /// Call `each` for each ancestor node of the one at `path` (not including
124 /// that node itself), starting from nearest the root.
114 /// Same as `get_node_mut`, and calls `each_ancestor` for each ancestor of
115 /// the node.
125 116 ///
126 /// Panics (possibly after some calls to `each`) if there is no node at
127 /// `path`.
128 fn for_each_ancestor_node<'tree>(
129 &mut self,
130 path: &HgPath,
131 each: impl FnMut(&mut Node),
132 ) {
133 let parent = path.parent();
134 if !parent.is_empty() {
135 Self::each_and_get(&mut self.root, parent, each)
136 .expect("missing dirstate node");
137 }
138 }
139
140 /// Common implementation detail of `get_node_mut` and
141 /// `for_each_ancestor_node`
142 fn each_and_get<'tree>(
117 /// Note that `each_ancestor` may be called (with what would be ancestors)
118 /// even if it turns out there is no node at `path`.
119 fn get_node_mut_tracing_ancestors<'tree>(
143 120 root: &'tree mut ChildNodes,
144 121 path: &HgPath,
145 mut each: impl FnMut(&mut Node),
122 mut each_ancestor: impl FnMut(&mut Node),
146 123 ) -> Option<&'tree mut Node> {
147 124 let mut children = root;
148 125 let mut components = path.components();
149 126 let mut component =
150 127 components.next().expect("expected at least one components");
151 128 loop {
152 129 let child = children.get_mut(component)?;
153 each(child);
154 130 if let Some(next_component) = components.next() {
131 each_ancestor(child);
155 132 component = next_component;
156 133 children = &mut child.children;
157 134 } else {
158 135 return Some(child);
159 136 }
160 137 }
161 138 }
162 139
163 140 fn get_or_insert_node<'tree>(
164 141 root: &'tree mut ChildNodes,
165 142 path: &HgPath,
166 143 ) -> &'tree mut Node {
144 Self::get_or_insert_node_tracing_ancestors(root, path, |_| {})
145 }
146
147 fn get_or_insert_node_tracing_ancestors<'tree>(
148 root: &'tree mut ChildNodes,
149 path: &HgPath,
150 mut each_ancestor: impl FnMut(&mut Node),
151 ) -> &'tree mut Node {
167 152 let mut child_nodes = root;
168 153 let mut inclusive_ancestor_paths =
169 154 WithBasename::inclusive_ancestors_of(path);
170 155 let mut ancestor_path = inclusive_ancestor_paths
171 156 .next()
172 157 .expect("expected at least one inclusive ancestor");
173 158 loop {
174 159 // TODO: can we avoid allocating an owned key in cases where the
175 160 // map already contains that key, without introducing double
176 161 // lookup?
177 162 let child_node =
178 163 child_nodes.entry(ancestor_path.to_owned()).or_default();
179 164 if let Some(next) = inclusive_ancestor_paths.next() {
165 each_ancestor(child_node);
180 166 ancestor_path = next;
181 167 child_nodes = &mut child_node.children;
182 168 } else {
183 169 return child_node;
184 170 }
185 171 }
186 172 }
187 173
188 /// The meaning of `new_copy_source` is:
189 ///
190 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
191 /// * `Some(None)`: set `Node::copy_source` to `None`
192 /// * `None`: leave `Node::copy_source` unchanged
193 fn add_file_node(
174 fn add_or_remove_file(
194 175 &mut self,
195 176 path: &HgPath,
177 old_state: EntryState,
196 178 new_entry: DirstateEntry,
197 new_copy_source: Option<Option<HgPathBuf>>,
198 179 ) {
199 let node = Self::get_or_insert_node(&mut self.root, path);
200 if node.entry.is_none() {
201 self.nodes_with_entry_count += 1
202 }
203 if let Some(source) = &new_copy_source {
204 if node.copy_source.is_none() && source.is_some() {
205 self.nodes_with_copy_source_count += 1
206 }
207 if node.copy_source.is_some() && source.is_none() {
208 self.nodes_with_copy_source_count -= 1
209 }
210 }
211 180 let tracked_count_increment =
212 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
181 match (old_state.is_tracked(), new_entry.state.is_tracked()) {
213 182 (false, true) => 1,
214 183 (true, false) => -1,
215 184 _ => 0,
216 185 };
217 186
218 node.entry = Some(new_entry);
219 if let Some(source) = new_copy_source {
220 node.copy_source = source
221 }
222 // Borrow of `self.root` through `node` ends here
223
187 let node = Self::get_or_insert_node_tracing_ancestors(
188 &mut self.root,
189 path,
190 |ancestor| {
191 // We can’t use `+= increment` because the counter is unsigned,
192 // and we want debug builds to detect accidental underflow
193 // through zero
224 194 match tracked_count_increment {
225 1 => self.for_each_ancestor_node(path, |node| {
226 node.tracked_descendants_count += 1
227 }),
228 // We can’t use `+= -1` because the counter is unsigned
229 -1 => self.for_each_ancestor_node(path, |node| {
230 node.tracked_descendants_count -= 1
231 }),
195 1 => ancestor.tracked_descendants_count += 1,
196 -1 => ancestor.tracked_descendants_count -= 1,
232 197 _ => {}
233 198 }
199 },
200 );
201 if node.entry.is_none() {
202 self.nodes_with_entry_count += 1
203 }
204 node.entry = Some(new_entry)
234 205 }
235 206
236 207 fn iter_nodes<'a>(
237 208 &'a self,
238 209 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
239 210 {
240 211 // Depth first tree traversal.
241 212 //
242 213 // If we could afford internal iteration and recursion,
243 214 // this would look like:
244 215 //
245 216 // ```
246 217 // fn traverse_children(
247 218 // children: &ChildNodes,
248 219 // each: &mut impl FnMut(&Node),
249 220 // ) {
250 221 // for child in children.values() {
251 222 // traverse_children(&child.children, each);
252 223 // each(child);
253 224 // }
254 225 // }
255 226 // ```
256 227 //
257 228 // However we want an external iterator and therefore can’t use the
258 229 // call stack. Use an explicit stack instead:
259 230 let mut stack = Vec::new();
260 231 let mut iter = self.root.iter();
261 232 std::iter::from_fn(move || {
262 233 while let Some((key, child_node)) = iter.next() {
263 234 // Pseudo-recursion
264 235 let new_iter = child_node.children.iter();
265 236 let old_iter = std::mem::replace(&mut iter, new_iter);
266 237 stack.push((key, child_node, old_iter));
267 238 }
268 239 // Found the end of a `children.iter()` iterator.
269 240 if let Some((key, child_node, next_iter)) = stack.pop() {
270 241 // "Return" from pseudo-recursion by restoring state from the
271 242 // explicit stack
272 243 iter = next_iter;
273 244
274 245 Some((key, child_node))
275 246 } else {
276 247 // Reached the bottom of the stack, we’re done
277 248 None
278 249 }
279 250 })
280 251 }
281 252
282 253 /// Mutable iterator for the `(entry, copy source)` of each node.
283 254 ///
284 255 /// It would not be safe to yield mutable references to nodes themeselves
285 256 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
286 257 /// reachable from their ancestor nodes, potentially creating multiple
287 258 /// `&mut` references to a given node.
288 259 fn iter_node_data_mut<'a>(
289 260 &'a mut self,
290 261 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
291 262 // Explict stack for pseudo-recursion, see `iter_nodes` above.
292 263 let mut stack = Vec::new();
293 264 let mut iter = self.root.iter_mut();
294 265 std::iter::from_fn(move || {
295 266 while let Some((key, child_node)) = iter.next() {
296 267 // Pseudo-recursion
297 268 let data =
298 269 (key, &mut child_node.entry, &mut child_node.copy_source);
299 270 let new_iter = child_node.children.iter_mut();
300 271 let old_iter = std::mem::replace(&mut iter, new_iter);
301 272 stack.push((data, old_iter));
302 273 }
303 274 // Found the end of a `children.values_mut()` iterator.
304 275 if let Some((data, next_iter)) = stack.pop() {
305 276 // "Return" from pseudo-recursion by restoring state from the
306 277 // explicit stack
307 278 iter = next_iter;
308 279
309 280 Some(data)
310 281 } else {
311 282 // Reached the bottom of the stack, we’re done
312 283 None
313 284 }
314 285 })
315 286 }
316 287 }
317 288
318 289 impl super::dispatch::DirstateMapMethods for DirstateMap {
319 290 fn clear(&mut self) {
320 291 self.set_parents(&DirstateParents {
321 292 p1: NULL_NODE,
322 293 p2: NULL_NODE,
323 294 });
324 295 self.root.clear();
325 296 self.nodes_with_entry_count = 0;
326 297 self.nodes_with_copy_source_count = 0;
327 298 }
328 299
329 300 fn add_file(
330 301 &mut self,
331 302 filename: &HgPath,
332 _old_state: EntryState,
303 old_state: EntryState,
333 304 entry: DirstateEntry,
334 305 ) -> Result<(), DirstateMapError> {
335 self.add_file_node(filename, entry, None);
306 self.add_or_remove_file(filename, old_state, entry);
336 307 Ok(())
337 308 }
338 309
339 310 fn remove_file(
340 311 &mut self,
341 312 filename: &HgPath,
342 _old_state: EntryState,
313 old_state: EntryState,
343 314 size: i32,
344 315 ) -> Result<(), DirstateMapError> {
345 316 let entry = DirstateEntry {
346 317 state: EntryState::Removed,
347 318 mode: 0,
348 319 size,
349 320 mtime: 0,
350 321 };
351 self.add_file_node(filename, entry, None);
322 self.add_or_remove_file(filename, old_state, entry);
352 323 Ok(())
353 324 }
354 325
355 326 fn drop_file(
356 327 &mut self,
357 328 filename: &HgPath,
358 _old_state: EntryState,
329 old_state: EntryState,
359 330 ) -> Result<bool, DirstateMapError> {
360 if let Some(node) = Self::get_node_mut(&mut self.root, filename) {
361 let was_tracked = node.is_tracked_file();
331 let was_tracked = old_state.is_tracked();
332 if let Some(node) = Self::get_node_mut_tracing_ancestors(
333 &mut self.root,
334 filename,
335 |ancestor| {
336 if was_tracked {
337 ancestor.tracked_descendants_count -= 1
338 }
339 },
340 ) {
362 341 let had_entry = node.entry.is_some();
363 342 let had_copy_source = node.copy_source.is_some();
364 343
365 344 // TODO: this leaves in the tree a "non-file" node. Should we
366 345 // remove the node instead, together with ancestor nodes for
367 346 // directories that become empty?
368 347 node.entry = None;
369 348 node.copy_source = None;
370 349
371 350 if had_entry {
372 351 self.nodes_with_entry_count -= 1
373 352 }
374 353 if had_copy_source {
375 354 self.nodes_with_copy_source_count -= 1
376 355 }
377 if was_tracked {
378 self.for_each_ancestor_node(filename, |node| {
379 node.tracked_descendants_count -= 1
380 })
381 }
382 356 Ok(had_entry)
383 357 } else {
358 assert!(!was_tracked);
384 359 Ok(false)
385 360 }
386 361 }
387 362
388 363 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
389 364 for filename in filenames {
390 365 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
391 366 if let Some(entry) = node.entry.as_mut() {
392 367 clear_ambiguous_mtime(entry, now);
393 368 }
394 369 }
395 370 }
396 371 }
397 372
398 373 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
399 374 self.get_node(key)
400 375 .and_then(|node| node.entry.as_ref())
401 376 .map_or(false, DirstateEntry::is_non_normal)
402 377 }
403 378
404 379 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
405 380 // Do nothing, this `DirstateMap` does not have a separate "non normal
406 381 // entries" set that need to be kept up to date
407 382 }
408 383
409 384 fn non_normal_or_other_parent_paths(
410 385 &mut self,
411 386 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
412 387 Box::new(self.iter_nodes().filter_map(|(path, node)| {
413 388 node.entry
414 389 .as_ref()
415 390 .filter(|entry| {
416 391 entry.is_non_normal() || entry.is_from_other_parent()
417 392 })
418 393 .map(|_| path.full_path())
419 394 }))
420 395 }
421 396
422 397 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
423 398 // Do nothing, this `DirstateMap` does not have a separate "non normal
424 399 // entries" and "from other parent" sets that need to be recomputed
425 400 }
426 401
427 402 fn iter_non_normal_paths(
428 403 &mut self,
429 404 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
430 405 self.iter_non_normal_paths_panic()
431 406 }
432 407
433 408 fn iter_non_normal_paths_panic(
434 409 &self,
435 410 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
436 411 Box::new(self.iter_nodes().filter_map(|(path, node)| {
437 412 node.entry
438 413 .as_ref()
439 414 .filter(|entry| entry.is_non_normal())
440 415 .map(|_| path.full_path())
441 416 }))
442 417 }
443 418
444 419 fn iter_other_parent_paths(
445 420 &mut self,
446 421 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
447 422 Box::new(self.iter_nodes().filter_map(|(path, node)| {
448 423 node.entry
449 424 .as_ref()
450 425 .filter(|entry| entry.is_from_other_parent())
451 426 .map(|_| path.full_path())
452 427 }))
453 428 }
454 429
455 430 fn has_tracked_dir(
456 431 &mut self,
457 432 directory: &HgPath,
458 433 ) -> Result<bool, DirstateMapError> {
459 434 if let Some(node) = self.get_node(directory) {
460 435 // A node without a `DirstateEntry` was created to hold child
461 436 // nodes, and is therefore a directory.
462 437 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
463 438 } else {
464 439 Ok(false)
465 440 }
466 441 }
467 442
468 443 fn has_dir(
469 444 &mut self,
470 445 directory: &HgPath,
471 446 ) -> Result<bool, DirstateMapError> {
472 447 if let Some(node) = self.get_node(directory) {
473 448 // A node without a `DirstateEntry` was created to hold child
474 449 // nodes, and is therefore a directory.
475 450 Ok(node.entry.is_none())
476 451 } else {
477 452 Ok(false)
478 453 }
479 454 }
480 455
481 456 fn parents(
482 457 &mut self,
483 458 file_contents: &[u8],
484 459 ) -> Result<&DirstateParents, DirstateError> {
485 460 if self.parents.is_none() {
486 461 let parents = if !file_contents.is_empty() {
487 462 parse_dirstate_parents(file_contents)?.clone()
488 463 } else {
489 464 DirstateParents {
490 465 p1: NULL_NODE,
491 466 p2: NULL_NODE,
492 467 }
493 468 };
494 469 self.parents = Some(parents);
495 470 }
496 471 Ok(self.parents.as_ref().unwrap())
497 472 }
498 473
499 474 fn set_parents(&mut self, parents: &DirstateParents) {
500 475 self.parents = Some(parents.clone());
501 476 self.dirty_parents = true;
502 477 }
503 478
504 479 #[timed]
505 480 fn read<'a>(
506 481 &mut self,
507 482 file_contents: &'a [u8],
508 483 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
509 484 if file_contents.is_empty() {
510 485 return Ok(None);
511 486 }
512 487
513 488 let parents = parse_dirstate_entries(
514 489 file_contents,
515 490 |path, entry, copy_source| {
516 self.add_file_node(
491 let tracked = entry.state.is_tracked();
492 let node = Self::get_or_insert_node_tracing_ancestors(
493 &mut self.root,
517 494 path,
518 *entry,
519 Some(copy_source.map(HgPath::to_owned)),
520 )
495 |ancestor| {
496 if tracked {
497 ancestor.tracked_descendants_count += 1
498 }
499 },
500 );
501 assert!(
502 node.entry.is_none(),
503 "duplicate dirstate entry in read"
504 );
505 assert!(
506 node.copy_source.is_none(),
507 "duplicate dirstate entry in read"
508 );
509 node.entry = Some(*entry);
510 node.copy_source = copy_source.map(HgPath::to_owned);
511 self.nodes_with_entry_count += 1;
512 if copy_source.is_some() {
513 self.nodes_with_copy_source_count += 1
514 }
521 515 },
522 516 )?;
523 517
524 518 if !self.dirty_parents {
525 519 self.set_parents(parents);
526 520 }
527 521
528 522 Ok(Some(parents))
529 523 }
530 524
531 525 fn pack(
532 526 &mut self,
533 527 parents: DirstateParents,
534 528 now: Timestamp,
535 529 ) -> Result<Vec<u8>, DirstateError> {
536 530 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
537 531 // reallocations
538 532 let mut size = parents.as_bytes().len();
539 533 for (path, node) in self.iter_nodes() {
540 534 if node.entry.is_some() {
541 535 size += packed_entry_size(
542 536 path.full_path(),
543 537 node.copy_source.as_ref(),
544 538 )
545 539 }
546 540 }
547 541
548 542 let mut packed = Vec::with_capacity(size);
549 543 packed.extend(parents.as_bytes());
550 544
551 545 let now: i32 = now.0.try_into().expect("time overflow");
552 546 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
553 547 if let Some(entry) = opt_entry {
554 548 clear_ambiguous_mtime(entry, now);
555 549 pack_entry(
556 550 path.full_path(),
557 551 entry,
558 552 copy_source.as_ref(),
559 553 &mut packed,
560 554 );
561 555 }
562 556 }
563 557 self.dirty_parents = false;
564 558 Ok(packed)
565 559 }
566 560
567 561 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
568 562 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
569 563 // needs to be recomputed
570 564 Ok(())
571 565 }
572 566
573 567 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
574 568 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
575 569 // to be recomputed
576 570 Ok(())
577 571 }
578 572
579 573 fn status<'a>(
580 574 &'a mut self,
581 575 matcher: &'a (dyn Matcher + Sync),
582 576 root_dir: PathBuf,
583 577 ignore_files: Vec<PathBuf>,
584 578 options: StatusOptions,
585 579 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
586 580 {
587 581 super::status::status(self, matcher, root_dir, ignore_files, options)
588 582 }
589 583
590 584 fn copy_map_len(&self) -> usize {
591 585 self.nodes_with_copy_source_count
592 586 }
593 587
594 588 fn copy_map_iter(&self) -> CopyMapIter<'_> {
595 589 Box::new(self.iter_nodes().filter_map(|(path, node)| {
596 590 node.copy_source
597 591 .as_ref()
598 592 .map(|copy_source| (path.full_path(), copy_source))
599 593 }))
600 594 }
601 595
602 596 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
603 597 if let Some(node) = self.get_node(key) {
604 598 node.copy_source.is_some()
605 599 } else {
606 600 false
607 601 }
608 602 }
609 603
610 604 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
611 605 self.get_node(key)?.copy_source.as_ref()
612 606 }
613 607
614 608 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
615 609 let count = &mut self.nodes_with_copy_source_count;
616 610 Self::get_node_mut(&mut self.root, key).and_then(|node| {
617 611 if node.copy_source.is_some() {
618 612 *count -= 1
619 613 }
620 614 node.copy_source.take()
621 615 })
622 616 }
623 617
624 618 fn copy_map_insert(
625 619 &mut self,
626 620 key: HgPathBuf,
627 621 value: HgPathBuf,
628 622 ) -> Option<HgPathBuf> {
629 623 let node = Self::get_or_insert_node(&mut self.root, &key);
630 624 if node.copy_source.is_none() {
631 625 self.nodes_with_copy_source_count += 1
632 626 }
633 627 node.copy_source.replace(value)
634 628 }
635 629
636 630 fn len(&self) -> usize {
637 631 self.nodes_with_entry_count
638 632 }
639 633
640 634 fn contains_key(&self, key: &HgPath) -> bool {
641 635 self.get(key).is_some()
642 636 }
643 637
644 638 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
645 639 self.get_node(key)?.entry.as_ref()
646 640 }
647 641
648 642 fn iter(&self) -> StateMapIter<'_> {
649 643 Box::new(self.iter_nodes().filter_map(|(path, node)| {
650 644 node.entry.as_ref().map(|entry| (path.full_path(), entry))
651 645 }))
652 646 }
653 647 }
General Comments 0
You need to be logged in to leave comments. Login now