Show More
@@ -12,9 +12,9 b' use std::convert::TryInto;' | |||||
12 |
|
12 | |||
13 | pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>; |
|
13 | pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>; | |
14 |
|
14 | |||
15 |
type PathToken = |
|
15 | type PathToken = usize; | |
16 |
|
16 | |||
17 | #[derive(Clone, Debug, PartialEq)] |
|
17 | #[derive(Clone, Debug, PartialEq, Copy)] | |
18 | struct TimeStampedPathCopy { |
|
18 | struct TimeStampedPathCopy { | |
19 | /// revision at which the copy information was added |
|
19 | /// revision at which the copy information was added | |
20 | rev: Revision, |
|
20 | rev: Revision, | |
@@ -314,6 +314,37 b' enum Parent {' | |||||
314 | SecondParent, |
|
314 | SecondParent, | |
315 | } |
|
315 | } | |
316 |
|
316 | |||
|
317 | /// A small "tokenizer" responsible of turning full HgPath into lighter | |||
|
318 | /// PathToken | |||
|
319 | /// | |||
|
320 | /// Dealing with small object, like integer is much faster, so HgPath input are | |||
|
321 | /// turned into integer "PathToken" and converted back in the end. | |||
|
322 | #[derive(Clone, Debug, Default)] | |||
|
323 | struct TwoWayPathMap { | |||
|
324 | token: HashMap<HgPathBuf, PathToken>, | |||
|
325 | path: Vec<HgPathBuf>, | |||
|
326 | } | |||
|
327 | ||||
|
328 | impl TwoWayPathMap { | |||
|
329 | fn tokenize(&mut self, path: &HgPath) -> PathToken { | |||
|
330 | match self.token.get(path) { | |||
|
331 | Some(a) => *a, | |||
|
332 | None => { | |||
|
333 | let a = self.token.len(); | |||
|
334 | let buf = path.to_owned(); | |||
|
335 | self.path.push(buf.clone()); | |||
|
336 | self.token.insert(buf, a); | |||
|
337 | a | |||
|
338 | } | |||
|
339 | } | |||
|
340 | } | |||
|
341 | ||||
|
342 | fn untokenize(&self, token: PathToken) -> &HgPathBuf { | |||
|
343 | assert!(token < self.path.len(), format!("Unknown token: {}", token)); | |||
|
344 | &self.path[token] | |||
|
345 | } | |||
|
346 | } | |||
|
347 | ||||
317 | /// Same as mercurial.copies._combine_changeset_copies, but in Rust. |
|
348 | /// Same as mercurial.copies._combine_changeset_copies, but in Rust. | |
318 | /// |
|
349 | /// | |
319 | /// Arguments are: |
|
350 | /// Arguments are: | |
@@ -337,6 +368,8 b' pub fn combine_changeset_copies<A: Fn(Re' | |||||
337 | let mut all_copies = HashMap::new(); |
|
368 | let mut all_copies = HashMap::new(); | |
338 | let mut oracle = AncestorOracle::new(is_ancestor); |
|
369 | let mut oracle = AncestorOracle::new(is_ancestor); | |
339 |
|
370 | |||
|
371 | let mut path_map = TwoWayPathMap::default(); | |||
|
372 | ||||
340 | for rev in revs { |
|
373 | for rev in revs { | |
341 | let mut d: DataHolder<D> = DataHolder { data: None }; |
|
374 | let mut d: DataHolder<D> = DataHolder { data: None }; | |
342 | let (p1, p2, changes) = rev_info(rev, &mut d); |
|
375 | let (p1, p2, changes) = rev_info(rev, &mut d); | |
@@ -355,6 +388,7 b' pub fn combine_changeset_copies<A: Fn(Re' | |||||
355 | if let Some(parent_copies) = parent_copies { |
|
388 | if let Some(parent_copies) = parent_copies { | |
356 | // combine it with data for that revision |
|
389 | // combine it with data for that revision | |
357 | let vertex_copies = add_from_changes( |
|
390 | let vertex_copies = add_from_changes( | |
|
391 | &mut path_map, | |||
358 | &parent_copies, |
|
392 | &parent_copies, | |
359 | &changes, |
|
393 | &changes, | |
360 | Parent::FirstParent, |
|
394 | Parent::FirstParent, | |
@@ -374,6 +408,7 b' pub fn combine_changeset_copies<A: Fn(Re' | |||||
374 | if let Some(parent_copies) = parent_copies { |
|
408 | if let Some(parent_copies) = parent_copies { | |
375 | // combine it with data for that revision |
|
409 | // combine it with data for that revision | |
376 | let vertex_copies = add_from_changes( |
|
410 | let vertex_copies = add_from_changes( | |
|
411 | &mut path_map, | |||
377 | &parent_copies, |
|
412 | &parent_copies, | |
378 | &changes, |
|
413 | &changes, | |
379 | Parent::SecondParent, |
|
414 | Parent::SecondParent, | |
@@ -388,6 +423,7 b' pub fn combine_changeset_copies<A: Fn(Re' | |||||
388 | // If we got data from both parents, We need to combine |
|
423 | // If we got data from both parents, We need to combine | |
389 | // them. |
|
424 | // them. | |
390 | Some(copies) => Some(merge_copies_dict( |
|
425 | Some(copies) => Some(merge_copies_dict( | |
|
426 | &path_map, | |||
391 | vertex_copies, |
|
427 | vertex_copies, | |
392 | copies, |
|
428 | copies, | |
393 | &changes, |
|
429 | &changes, | |
@@ -412,7 +448,9 b' pub fn combine_changeset_copies<A: Fn(Re' | |||||
412 | let mut result = PathCopies::default(); |
|
448 | let mut result = PathCopies::default(); | |
413 | for (dest, tt_source) in tt_result { |
|
449 | for (dest, tt_source) in tt_result { | |
414 | if let Some(path) = tt_source.path { |
|
450 | if let Some(path) = tt_source.path { | |
415 | result.insert(dest, path); |
|
451 | let path_dest = path_map.untokenize(dest).to_owned(); | |
|
452 | let path_path = path_map.untokenize(path).to_owned(); | |||
|
453 | result.insert(path_dest, path_path); | |||
416 | } |
|
454 | } | |
417 | } |
|
455 | } | |
418 | result |
|
456 | result | |
@@ -447,6 +485,7 b' fn get_and_clean_parent_copies(' | |||||
447 | /// Combine ChangedFiles with some existing PathCopies information and return |
|
485 | /// Combine ChangedFiles with some existing PathCopies information and return | |
448 | /// the result |
|
486 | /// the result | |
449 | fn add_from_changes( |
|
487 | fn add_from_changes( | |
|
488 | path_map: &mut TwoWayPathMap, | |||
450 | base_copies: &TimeStampedPathCopies, |
|
489 | base_copies: &TimeStampedPathCopies, | |
451 | changes: &ChangedFiles, |
|
490 | changes: &ChangedFiles, | |
452 | parent: Parent, |
|
491 | parent: Parent, | |
@@ -455,9 +494,11 b' fn add_from_changes(' | |||||
455 | let mut copies = base_copies.clone(); |
|
494 | let mut copies = base_copies.clone(); | |
456 | for action in changes.iter_actions(parent) { |
|
495 | for action in changes.iter_actions(parent) { | |
457 | match action { |
|
496 | match action { | |
458 | Action::Copied(dest, source) => { |
|
497 | Action::Copied(path_dest, path_source) => { | |
|
498 | let dest = path_map.tokenize(path_dest); | |||
|
499 | let source = path_map.tokenize(path_source); | |||
459 | let entry; |
|
500 | let entry; | |
460 | if let Some(v) = base_copies.get(source) { |
|
501 | if let Some(v) = base_copies.get(&source) { | |
461 | entry = match &v.path { |
|
502 | entry = match &v.path { | |
462 | Some(path) => Some((*(path)).to_owned()), |
|
503 | Some(path) => Some((*(path)).to_owned()), | |
463 | None => Some(source.to_owned()), |
|
504 | None => Some(source.to_owned()), | |
@@ -475,18 +516,19 b' fn add_from_changes(' | |||||
475 | }; |
|
516 | }; | |
476 | copies.insert(dest.to_owned(), ttpc); |
|
517 | copies.insert(dest.to_owned(), ttpc); | |
477 | } |
|
518 | } | |
478 |
Action::Removed( |
|
519 | Action::Removed(deleted_path) => { | |
479 | // We must drop copy information for removed file. |
|
520 | // We must drop copy information for removed file. | |
480 | // |
|
521 | // | |
481 | // We need to explicitly record them as dropped to |
|
522 | // We need to explicitly record them as dropped to | |
482 | // propagate this information when merging two |
|
523 | // propagate this information when merging two | |
483 | // TimeStampedPathCopies object. |
|
524 | // TimeStampedPathCopies object. | |
484 | if copies.contains_key(f.as_ref()) { |
|
525 | let deleted = path_map.tokenize(deleted_path); | |
|
526 | if copies.contains_key(&deleted) { | |||
485 | let ttpc = TimeStampedPathCopy { |
|
527 | let ttpc = TimeStampedPathCopy { | |
486 | rev: current_rev, |
|
528 | rev: current_rev, | |
487 | path: None, |
|
529 | path: None, | |
488 | }; |
|
530 | }; | |
489 |
copies.insert( |
|
531 | copies.insert(deleted, ttpc); | |
490 | } |
|
532 | } | |
491 | } |
|
533 | } | |
492 | } |
|
534 | } | |
@@ -499,6 +541,7 b' fn add_from_changes(' | |||||
499 | /// In case of conflict, value from "major" will be picked, unless in some |
|
541 | /// In case of conflict, value from "major" will be picked, unless in some | |
500 | /// cases. See inline documentation for details. |
|
542 | /// cases. See inline documentation for details. | |
501 | fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( |
|
543 | fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( | |
|
544 | path_map: &TwoWayPathMap, | |||
502 | mut minor: TimeStampedPathCopies, |
|
545 | mut minor: TimeStampedPathCopies, | |
503 | mut major: TimeStampedPathCopies, |
|
546 | mut major: TimeStampedPathCopies, | |
504 | changes: &ChangedFiles, |
|
547 | changes: &ChangedFiles, | |
@@ -511,7 +554,9 b' fn merge_copies_dict<A: Fn(Revision, Rev' | |||||
511 | |dest: &PathToken, |
|
554 | |dest: &PathToken, | |
512 | src_minor: &TimeStampedPathCopy, |
|
555 | src_minor: &TimeStampedPathCopy, | |
513 | src_major: &TimeStampedPathCopy| { |
|
556 | src_major: &TimeStampedPathCopy| { | |
514 | compare_value(changes, oracle, dest, src_minor, src_major) |
|
557 | compare_value( | |
|
558 | path_map, changes, oracle, dest, src_minor, src_major, | |||
|
559 | ) | |||
515 | }; |
|
560 | }; | |
516 | if minor.is_empty() { |
|
561 | if minor.is_empty() { | |
517 | major |
|
562 | major | |
@@ -641,6 +686,7 b' enum MergePick {' | |||||
641 | /// decide which side prevails in case of conflicting values |
|
686 | /// decide which side prevails in case of conflicting values | |
642 | #[allow(clippy::if_same_then_else)] |
|
687 | #[allow(clippy::if_same_then_else)] | |
643 | fn compare_value<A: Fn(Revision, Revision) -> bool>( |
|
688 | fn compare_value<A: Fn(Revision, Revision) -> bool>( | |
|
689 | path_map: &TwoWayPathMap, | |||
644 | changes: &ChangedFiles, |
|
690 | changes: &ChangedFiles, | |
645 | oracle: &mut AncestorOracle<A>, |
|
691 | oracle: &mut AncestorOracle<A>, | |
646 | dest: &PathToken, |
|
692 | dest: &PathToken, | |
@@ -664,7 +710,8 b' fn compare_value<A: Fn(Revision, Revisio' | |||||
664 | "conflict information from p1 and p2 in the same revision" |
|
710 | "conflict information from p1 and p2 in the same revision" | |
665 | ); |
|
711 | ); | |
666 | } else { |
|
712 | } else { | |
667 | let action = changes.get_merge_case(&dest); |
|
713 | let dest_path = path_map.untokenize(*dest); | |
|
714 | let action = changes.get_merge_case(dest_path); | |||
668 | if src_major.path.is_none() && action == MergeCase::Salvaged { |
|
715 | if src_major.path.is_none() && action == MergeCase::Salvaged { | |
669 | // If the file is "deleted" in the major side but was |
|
716 | // If the file is "deleted" in the major side but was | |
670 | // salvaged by the merge, we keep the minor side alive |
|
717 | // salvaged by the merge, we keep the minor side alive |
General Comments 0
You need to be logged in to leave comments.
Login now