comparison rust/hg-core/src/copy_tracing.rs @ 45973:ed0e1339e4a8

copies-rust: combine the iteration over remove and copies into one In the underlying data, the copies information and the removal information are interleaved. And in the consumer code, the consumption could be interleaved too. So, we make the processing closer to the underlying data by fusing the two iterators into one. Later, we will directly consume the underlying data and that logic to combine the two iterators will be unnecessary. Differential Revision: https://phab.mercurial-scm.org/D9304
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 05 Oct 2020 01:31:32 +0200
parents 8b99c473aae2
children 10bb0856bb9f
comparison
equal deleted inserted replaced
45972:8b99c473aae2 45973:ed0e1339e4a8
1 use crate::utils::hg_path::HgPath;
1 use crate::utils::hg_path::HgPathBuf; 2 use crate::utils::hg_path::HgPathBuf;
2 use crate::Revision; 3 use crate::Revision;
3 4
4 use im_rc::ordmap::DiffItem; 5 use im_rc::ordmap::DiffItem;
5 use im_rc::ordmap::OrdMap; 6 use im_rc::ordmap::OrdMap;
32 removed: HashSet<HgPathBuf>, 33 removed: HashSet<HgPathBuf>,
33 merged: HashSet<HgPathBuf>, 34 merged: HashSet<HgPathBuf>,
34 salvaged: HashSet<HgPathBuf>, 35 salvaged: HashSet<HgPathBuf>,
35 copied_from_p1: PathCopies, 36 copied_from_p1: PathCopies,
36 copied_from_p2: PathCopies, 37 copied_from_p2: PathCopies,
38 }
39
40 /// Represent active changes that affect the copy tracing.
41 enum Action<'a> {
42 /// The parent ? children edge is removing a file
43 ///
44 /// (actually, this could be the edge from the other parent, but it does
45 /// not matters)
46 Removed(&'a HgPath),
47 /// The parent ? children edge introduce copy information between (dest,
48 /// source)
49 Copied(&'a HgPath, &'a HgPath),
37 } 50 }
38 51
39 impl ChangedFiles { 52 impl ChangedFiles {
40 pub fn new( 53 pub fn new(
41 removed: HashSet<HgPathBuf>, 54 removed: HashSet<HgPathBuf>,
59 merged: HashSet::new(), 72 merged: HashSet::new(),
60 salvaged: HashSet::new(), 73 salvaged: HashSet::new(),
61 copied_from_p1: PathCopies::new(), 74 copied_from_p1: PathCopies::new(),
62 copied_from_p2: PathCopies::new(), 75 copied_from_p2: PathCopies::new(),
63 } 76 }
77 }
78
79 /// Return an iterator over all the `Action` in this instance.
80 fn iter_actions(&self, parent: usize) -> impl Iterator<Item = Action> {
81 let copies_iter = match parent {
82 1 => self.copied_from_p1.iter(),
83 2 => self.copied_from_p2.iter(),
84 _ => unreachable!(),
85 };
86 let remove_iter = self.removed.iter();
87 let copies_iter = copies_iter.map(|(x, y)| Action::Copied(x, y));
88 let remove_iter = remove_iter.map(|x| Action::Removed(x));
89 copies_iter.chain(remove_iter)
64 } 90 }
65 } 91 }
66 92
67 /// A struct responsible for answering "is X ancestors of Y" quickly 93 /// A struct responsible for answering "is X ancestors of Y" quickly
68 /// 94 ///
140 // We will chain the copies information accumulated for `rev` with 166 // We will chain the copies information accumulated for `rev` with
141 // the individual copies information for each of its children. 167 // the individual copies information for each of its children.
142 // Creating a new PathCopies for each `rev` ? `children` vertex. 168 // Creating a new PathCopies for each `rev` ? `children` vertex.
143 let (p1, p2, changes) = rev_info(*child); 169 let (p1, p2, changes) = rev_info(*child);
144 170
145 let (parent, child_copies) = if rev == p1 { 171 let parent = if rev == p1 {
146 (1, &changes.copied_from_p1) 172 1
147 } else { 173 } else {
148 assert_eq!(rev, p2); 174 assert_eq!(rev, p2);
149 (2, &changes.copied_from_p2) 175 2
150 }; 176 };
151 let mut new_copies = copies.clone(); 177 let mut new_copies = copies.clone();
152 178
153 for (dest, source) in child_copies { 179 for action in changes.iter_actions(parent) {
154 let entry; 180 match action {
155 if let Some(v) = copies.get(source) { 181 Action::Copied(dest, source) => {
156 entry = match &v.path { 182 let entry;
157 Some(path) => Some((*(path)).to_owned()), 183 if let Some(v) = copies.get(source) {
158 None => Some(source.to_owned()), 184 entry = match &v.path {
185 Some(path) => Some((*(path)).to_owned()),
186 None => Some(source.to_owned()),
187 }
188 } else {
189 entry = Some(source.to_owned());
190 }
191 // Each new entry is introduced by the children, we
192 // record this information as we will need it to take
193 // the right decision when merging conflicting copy
194 // information. See merge_copies_dict for details.
195 let ttpc = TimeStampedPathCopy {
196 rev: *child,
197 path: entry,
198 };
199 new_copies.insert(dest.to_owned(), ttpc);
159 } 200 }
160 } else { 201 Action::Removed(f) => {
161 entry = Some(source.to_owned()); 202 // We must drop copy information for removed file.
162 } 203 //
163 // Each new entry is introduced by the children, we record this 204 // We need to explicitly record them as dropped to
164 // information as we will need it to take the right decision 205 // propagate this information when merging two
165 // when merging conflicting copy information. See 206 // TimeStampedPathCopies object.
166 // merge_copies_dict for details. 207 if new_copies.contains_key(f.as_ref()) {
167 let ttpc = TimeStampedPathCopy { 208 let ttpc = TimeStampedPathCopy {
168 rev: *child, 209 rev: *child,
169 path: entry, 210 path: None,
170 }; 211 };
171 new_copies.insert(dest.to_owned(), ttpc); 212 new_copies.insert(f.to_owned(), ttpc);
172 } 213 }
173 214 }
174 // We must drop copy information for removed file.
175 //
176 // We need to explicitly record them as dropped to propagate this
177 // information when merging two TimeStampedPathCopies object.
178 for f in changes.removed.iter() {
179 if new_copies.contains_key(f.as_ref()) {
180 let ttpc = TimeStampedPathCopy {
181 rev: *child,
182 path: None,
183 };
184 new_copies.insert(f.to_owned(), ttpc);
185 } 215 }
186 } 216 }
187 217
188 // Merge has two parents needs to combines their copy information. 218 // Merge has two parents needs to combines their copy information.
189 // 219 //