##// END OF EJS Templates
copies-rust: tokenize all paths into integer...
marmoute -
r46766:c6bc77f7 default
parent child Browse files
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 = HgPathBuf;
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(f) => {
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(f.to_owned(), ttpc);
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