Mercurial > hg
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 // |