##// END OF EJS Templates
dirstate-tree: Add copy_map_insert and copy_map_remove...
Simon Sapin -
r47874:fdf6cfa0 default
parent child Browse files
Show More
@@ -1,495 +1,524 b''
1 1 use bytes_cast::BytesCast;
2 2 use std::path::PathBuf;
3 3 use std::{collections::BTreeMap, convert::TryInto};
4 4
5 5 use super::path_with_basename::WithBasename;
6 6 use crate::dirstate::parsers::clear_ambiguous_mtime;
7 7 use crate::dirstate::parsers::pack_entry;
8 8 use crate::dirstate::parsers::packed_entry_size;
9 9 use crate::dirstate::parsers::parse_dirstate_entries;
10 10 use crate::dirstate::parsers::parse_dirstate_parents;
11 11 use crate::dirstate::parsers::Timestamp;
12 12 use crate::matchers::Matcher;
13 13 use crate::revlog::node::NULL_NODE;
14 14 use crate::utils::hg_path::{HgPath, HgPathBuf};
15 15 use crate::CopyMapIter;
16 16 use crate::DirstateEntry;
17 17 use crate::DirstateError;
18 18 use crate::DirstateMapError;
19 19 use crate::DirstateParents;
20 20 use crate::DirstateStatus;
21 21 use crate::EntryState;
22 22 use crate::FastHashMap;
23 23 use crate::HgPathCow;
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 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 type ChildNodes = BTreeMap<WithBasename<HgPathBuf>, Node>;
48 48
49 49 #[derive(Default)]
50 50 struct Node {
51 51 entry: Option<DirstateEntry>,
52 52 copy_source: Option<HgPathBuf>,
53 53 children: ChildNodes,
54 54 }
55 55
56 56 /// `(full_path, entry, copy_source)`
57 57 type NodeDataMut<'a> = (
58 58 &'a WithBasename<HgPathBuf>,
59 59 &'a mut Option<DirstateEntry>,
60 60 &'a mut Option<HgPathBuf>,
61 61 );
62 62
63 63 impl DirstateMap {
64 64 pub fn new() -> Self {
65 65 Self {
66 66 parents: None,
67 67 dirty_parents: false,
68 68 root: ChildNodes::new(),
69 69 nodes_with_entry_count: 0,
70 70 nodes_with_copy_source_count: 0,
71 71 }
72 72 }
73 73
74 74 fn get_node(&self, path: &HgPath) -> Option<&Node> {
75 75 let mut children = &self.root;
76 76 let mut components = path.components();
77 77 let mut component =
78 78 components.next().expect("expected at least one components");
79 79 loop {
80 80 let child = children.get(component)?;
81 81 if let Some(next_component) = components.next() {
82 82 component = next_component;
83 83 children = &child.children;
84 84 } else {
85 85 return Some(child);
86 86 }
87 87 }
88 88 }
89 89
90 90 /// This takes `root` instead of `&mut self` so that callers can mutate
91 91 /// other fields while the returned borrow is still valid
92 fn get_node_mut<'tree>(
93 root: &'tree mut ChildNodes,
94 path: &HgPath,
95 ) -> Option<&'tree mut Node> {
96 let mut children = root;
97 let mut components = path.components();
98 let mut component =
99 components.next().expect("expected at least one components");
100 loop {
101 let child = children.get_mut(component)?;
102 if let Some(next_component) = components.next() {
103 component = next_component;
104 children = &mut child.children;
105 } else {
106 return Some(child);
107 }
108 }
109 }
110
92 111 fn get_or_insert_node<'tree>(
93 112 root: &'tree mut ChildNodes,
94 113 path: &HgPath,
95 114 ) -> &'tree mut Node {
96 115 let mut child_nodes = root;
97 116 let mut inclusive_ancestor_paths =
98 117 WithBasename::inclusive_ancestors_of(path);
99 118 let mut ancestor_path = inclusive_ancestor_paths
100 119 .next()
101 120 .expect("expected at least one inclusive ancestor");
102 121 loop {
103 122 // TODO: can we avoid double lookup in all cases without allocating
104 123 // an owned key in cases where the map already contains that key?
105 124 let child_node =
106 125 if child_nodes.contains_key(ancestor_path.base_name()) {
107 126 child_nodes.get_mut(ancestor_path.base_name()).unwrap()
108 127 } else {
109 128 // This is always a vacant entry, using `.entry()` lets us
110 129 // return a `&mut Node` of the newly-inserted node without
111 130 // yet another lookup. `BTreeMap::insert` doesn’t do this.
112 131 child_nodes.entry(ancestor_path.to_owned()).or_default()
113 132 };
114 133 if let Some(next) = inclusive_ancestor_paths.next() {
115 134 ancestor_path = next;
116 135 child_nodes = &mut child_node.children;
117 136 } else {
118 137 return child_node;
119 138 }
120 139 }
121 140 }
122 141
123 142 /// The meaning of `new_copy_source` is:
124 143 ///
125 144 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
126 145 /// * `Some(None)`: set `Node::copy_source` to `None`
127 146 /// * `None`: leave `Node::copy_source` unchanged
128 147 fn add_file_node(
129 148 &mut self,
130 149 path: &HgPath,
131 150 new_entry: DirstateEntry,
132 151 new_copy_source: Option<Option<HgPathBuf>>,
133 152 ) {
134 153 let node = Self::get_or_insert_node(&mut self.root, path);
135 154 if node.entry.is_none() {
136 155 self.nodes_with_entry_count += 1
137 156 }
138 157 if let Some(source) = &new_copy_source {
139 158 if node.copy_source.is_none() && source.is_some() {
140 159 self.nodes_with_copy_source_count += 1
141 160 }
142 161 if node.copy_source.is_some() && source.is_none() {
143 162 self.nodes_with_copy_source_count -= 1
144 163 }
145 164 }
146 165 node.entry = Some(new_entry);
147 166 if let Some(source) = new_copy_source {
148 167 node.copy_source = source
149 168 }
150 169 }
151 170
152 171 fn iter_nodes<'a>(
153 172 &'a self,
154 173 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
155 174 {
156 175 // Depth first tree traversal.
157 176 //
158 177 // If we could afford internal iteration and recursion,
159 178 // this would look like:
160 179 //
161 180 // ```
162 181 // fn traverse_children(
163 182 // children: &ChildNodes,
164 183 // each: &mut impl FnMut(&Node),
165 184 // ) {
166 185 // for child in children.values() {
167 186 // traverse_children(&child.children, each);
168 187 // each(child);
169 188 // }
170 189 // }
171 190 // ```
172 191 //
173 192 // However we want an external iterator and therefore can’t use the
174 193 // call stack. Use an explicit stack instead:
175 194 let mut stack = Vec::new();
176 195 let mut iter = self.root.iter();
177 196 std::iter::from_fn(move || {
178 197 while let Some((key, child_node)) = iter.next() {
179 198 // Pseudo-recursion
180 199 let new_iter = child_node.children.iter();
181 200 let old_iter = std::mem::replace(&mut iter, new_iter);
182 201 stack.push((key, child_node, old_iter));
183 202 }
184 203 // Found the end of a `children.iter()` iterator.
185 204 if let Some((key, child_node, next_iter)) = stack.pop() {
186 205 // "Return" from pseudo-recursion by restoring state from the
187 206 // explicit stack
188 207 iter = next_iter;
189 208
190 209 Some((key, child_node))
191 210 } else {
192 211 // Reached the bottom of the stack, we’re done
193 212 None
194 213 }
195 214 })
196 215 }
197 216
198 217 /// Mutable iterator for the `(entry, copy source)` of each node.
199 218 ///
200 219 /// It would not be safe to yield mutable references to nodes themeselves
201 220 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
202 221 /// reachable from their ancestor nodes, potentially creating multiple
203 222 /// `&mut` references to a given node.
204 223 fn iter_node_data_mut<'a>(
205 224 &'a mut self,
206 225 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
207 226 // Explict stack for pseudo-recursion, see `iter_nodes` above.
208 227 let mut stack = Vec::new();
209 228 let mut iter = self.root.iter_mut();
210 229 std::iter::from_fn(move || {
211 230 while let Some((key, child_node)) = iter.next() {
212 231 // Pseudo-recursion
213 232 let data =
214 233 (key, &mut child_node.entry, &mut child_node.copy_source);
215 234 let new_iter = child_node.children.iter_mut();
216 235 let old_iter = std::mem::replace(&mut iter, new_iter);
217 236 stack.push((data, old_iter));
218 237 }
219 238 // Found the end of a `children.values_mut()` iterator.
220 239 if let Some((data, next_iter)) = stack.pop() {
221 240 // "Return" from pseudo-recursion by restoring state from the
222 241 // explicit stack
223 242 iter = next_iter;
224 243
225 244 Some(data)
226 245 } else {
227 246 // Reached the bottom of the stack, we’re done
228 247 None
229 248 }
230 249 })
231 250 }
232 251 }
233 252
234 253 impl super::dispatch::DirstateMapMethods for DirstateMap {
235 254 fn clear(&mut self) {
236 255 self.set_parents(&DirstateParents {
237 256 p1: NULL_NODE,
238 257 p2: NULL_NODE,
239 258 });
240 259 self.root.clear();
241 260 self.nodes_with_entry_count = 0;
242 261 self.nodes_with_copy_source_count = 0;
243 262 }
244 263
245 264 fn add_file(
246 265 &mut self,
247 266 _filename: &HgPath,
248 267 _old_state: EntryState,
249 268 _entry: DirstateEntry,
250 269 ) -> Result<(), DirstateMapError> {
251 270 todo!()
252 271 }
253 272
254 273 fn remove_file(
255 274 &mut self,
256 275 _filename: &HgPath,
257 276 _old_state: EntryState,
258 277 _size: i32,
259 278 ) -> Result<(), DirstateMapError> {
260 279 todo!()
261 280 }
262 281
263 282 fn drop_file(
264 283 &mut self,
265 284 _filename: &HgPath,
266 285 _old_state: EntryState,
267 286 ) -> Result<bool, DirstateMapError> {
268 287 todo!()
269 288 }
270 289
271 290 fn clear_ambiguous_times(
272 291 &mut self,
273 292 _filenames: Vec<HgPathBuf>,
274 293 _now: i32,
275 294 ) {
276 295 todo!()
277 296 }
278 297
279 298 fn non_normal_entries_contains(&mut self, _key: &HgPath) -> bool {
280 299 todo!()
281 300 }
282 301
283 302 fn non_normal_entries_remove(&mut self, _key: &HgPath) -> bool {
284 303 todo!()
285 304 }
286 305
287 306 fn non_normal_or_other_parent_paths(
288 307 &mut self,
289 308 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
290 309 todo!()
291 310 }
292 311
293 312 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
294 313 todo!()
295 314 }
296 315
297 316 fn iter_non_normal_paths(
298 317 &mut self,
299 318 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
300 319 todo!()
301 320 }
302 321
303 322 fn iter_non_normal_paths_panic(
304 323 &self,
305 324 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
306 325 todo!()
307 326 }
308 327
309 328 fn iter_other_parent_paths(
310 329 &mut self,
311 330 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
312 331 todo!()
313 332 }
314 333
315 334 fn has_tracked_dir(
316 335 &mut self,
317 336 _directory: &HgPath,
318 337 ) -> Result<bool, DirstateMapError> {
319 338 todo!()
320 339 }
321 340
322 341 fn has_dir(
323 342 &mut self,
324 343 _directory: &HgPath,
325 344 ) -> Result<bool, DirstateMapError> {
326 345 todo!()
327 346 }
328 347
329 348 fn parents(
330 349 &mut self,
331 350 file_contents: &[u8],
332 351 ) -> Result<&DirstateParents, DirstateError> {
333 352 if self.parents.is_none() {
334 353 let parents = if !file_contents.is_empty() {
335 354 parse_dirstate_parents(file_contents)?.clone()
336 355 } else {
337 356 DirstateParents {
338 357 p1: NULL_NODE,
339 358 p2: NULL_NODE,
340 359 }
341 360 };
342 361 self.parents = Some(parents);
343 362 }
344 363 Ok(self.parents.as_ref().unwrap())
345 364 }
346 365
347 366 fn set_parents(&mut self, parents: &DirstateParents) {
348 367 self.parents = Some(parents.clone());
349 368 self.dirty_parents = true;
350 369 }
351 370
352 371 fn read<'a>(
353 372 &mut self,
354 373 file_contents: &'a [u8],
355 374 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
356 375 if file_contents.is_empty() {
357 376 return Ok(None);
358 377 }
359 378
360 379 let parents = parse_dirstate_entries(
361 380 file_contents,
362 381 |path, entry, copy_source| {
363 382 self.add_file_node(
364 383 path,
365 384 *entry,
366 385 Some(copy_source.map(HgPath::to_owned)),
367 386 )
368 387 },
369 388 )?;
370 389
371 390 if !self.dirty_parents {
372 391 self.set_parents(parents);
373 392 }
374 393
375 394 Ok(Some(parents))
376 395 }
377 396
378 397 fn pack(
379 398 &mut self,
380 399 parents: DirstateParents,
381 400 now: Timestamp,
382 401 ) -> Result<Vec<u8>, DirstateError> {
383 402 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
384 403 // reallocations
385 404 let mut size = parents.as_bytes().len();
386 405 for (path, node) in self.iter_nodes() {
387 406 if node.entry.is_some() {
388 407 size += packed_entry_size(
389 408 path.full_path(),
390 409 node.copy_source.as_ref(),
391 410 )
392 411 }
393 412 }
394 413
395 414 let mut packed = Vec::with_capacity(size);
396 415 packed.extend(parents.as_bytes());
397 416
398 417 let now: i32 = now.0.try_into().expect("time overflow");
399 418 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
400 419 if let Some(entry) = opt_entry {
401 420 clear_ambiguous_mtime(entry, now);
402 421 pack_entry(
403 422 path.full_path(),
404 423 entry,
405 424 copy_source.as_ref(),
406 425 &mut packed,
407 426 );
408 427 }
409 428 }
410 429 self.dirty_parents = false;
411 430 Ok(packed)
412 431 }
413 432
414 433 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
415 434 todo!()
416 435 }
417 436
418 437 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
419 438 todo!()
420 439 }
421 440
422 441 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
423 442 todo!()
424 443 }
425 444
426 445 fn status<'a>(
427 446 &'a self,
428 447 _matcher: &'a (dyn Matcher + Sync),
429 448 _root_dir: PathBuf,
430 449 _ignore_files: Vec<PathBuf>,
431 450 _options: StatusOptions,
432 451 ) -> Result<
433 452 (
434 453 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
435 454 Vec<PatternFileWarning>,
436 455 ),
437 456 StatusError,
438 457 > {
439 458 todo!()
440 459 }
441 460
442 461 fn copy_map_len(&self) -> usize {
443 462 self.nodes_with_copy_source_count
444 463 }
445 464
446 465 fn copy_map_iter(&self) -> CopyMapIter<'_> {
447 466 Box::new(self.iter_nodes().filter_map(|(path, node)| {
448 467 node.copy_source
449 468 .as_ref()
450 469 .map(|copy_source| (path.full_path(), copy_source))
451 470 }))
452 471 }
453 472
454 473 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
455 474 if let Some(node) = self.get_node(key) {
456 475 node.copy_source.is_some()
457 476 } else {
458 477 false
459 478 }
460 479 }
461 480
462 481 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
463 482 self.get_node(key)?.copy_source.as_ref()
464 483 }
465 484
466 fn copy_map_remove(&mut self, _key: &HgPath) -> Option<HgPathBuf> {
467 todo!()
485 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
486 let count = &mut self.nodes_with_copy_source_count;
487 Self::get_node_mut(&mut self.root, key).and_then(|node| {
488 if node.copy_source.is_some() {
489 *count -= 1
490 }
491 node.copy_source.take()
492 })
468 493 }
469 494
470 495 fn copy_map_insert(
471 496 &mut self,
472 _key: HgPathBuf,
473 _value: HgPathBuf,
497 key: HgPathBuf,
498 value: HgPathBuf,
474 499 ) -> Option<HgPathBuf> {
475 todo!()
500 let node = Self::get_or_insert_node(&mut self.root, &key);
501 if node.copy_source.is_none() {
502 self.nodes_with_copy_source_count += 1
503 }
504 node.copy_source.replace(value)
476 505 }
477 506
478 507 fn len(&self) -> usize {
479 508 self.nodes_with_entry_count
480 509 }
481 510
482 511 fn contains_key(&self, key: &HgPath) -> bool {
483 512 self.get(key).is_some()
484 513 }
485 514
486 515 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
487 516 self.get_node(key)?.entry.as_ref()
488 517 }
489 518
490 519 fn iter(&self) -> StateMapIter<'_> {
491 520 Box::new(self.iter_nodes().filter_map(|(path, node)| {
492 521 node.entry.as_ref().map(|entry| (path.full_path(), entry))
493 522 }))
494 523 }
495 524 }
General Comments 0
You need to be logged in to leave comments. Login now