Show More
@@ -259,7 +259,7 b' def _changesetforwardcopies(a, b, match)' | |||||
259 | children = {} |
|
259 | children = {} | |
260 |
|
260 | |||
261 | cl = repo.changelog |
|
261 | cl = repo.changelog | |
262 |
isancestor = |
|
262 | isancestor = cl.isancestorrev | |
263 | missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()]) |
|
263 | missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()]) | |
264 | mrset = set(missingrevs) |
|
264 | mrset = set(missingrevs) | |
265 | roots = set() |
|
265 | roots = set() | |
@@ -321,6 +321,8 b' def _combine_changeset_copies(' | |||||
321 | list(revs), children, targetrev, revinfo, isancestor |
|
321 | list(revs), children, targetrev, revinfo, isancestor | |
322 | ) |
|
322 | ) | |
323 |
|
323 | |||
|
324 | isancestor = cached_is_ancestor(isancestor) | |||
|
325 | ||||
324 | all_copies = {} |
|
326 | all_copies = {} | |
325 | for r in revs: |
|
327 | for r in revs: | |
326 | copies = all_copies.pop(r, None) |
|
328 | copies = all_copies.pop(r, None) |
@@ -64,6 +64,42 b' impl ChangedFiles {' | |||||
64 | } |
|
64 | } | |
65 | } |
|
65 | } | |
66 |
|
66 | |||
|
67 | /// A struct responsible for answering "is X ancestors of Y" quickly | |||
|
68 | /// | |||
|
69 | /// The structure will delegate ancestors call to a callback, and cache the | |||
|
70 | /// result. | |||
|
71 | #[derive(Debug)] | |||
|
72 | struct AncestorOracle<'a, A: Fn(Revision, Revision) -> bool> { | |||
|
73 | inner: &'a A, | |||
|
74 | pairs: HashMap<(Revision, Revision), bool>, | |||
|
75 | } | |||
|
76 | ||||
|
77 | impl<'a, A: Fn(Revision, Revision) -> bool> AncestorOracle<'a, A> { | |||
|
78 | fn new(func: &'a A) -> Self { | |||
|
79 | Self { | |||
|
80 | inner: func, | |||
|
81 | pairs: HashMap::default(), | |||
|
82 | } | |||
|
83 | } | |||
|
84 | ||||
|
85 | /// returns `true` if `anc` is an ancestors of `desc`, `false` otherwise | |||
|
86 | fn is_ancestor(&mut self, anc: Revision, desc: Revision) -> bool { | |||
|
87 | if anc > desc { | |||
|
88 | false | |||
|
89 | } else if anc == desc { | |||
|
90 | true | |||
|
91 | } else { | |||
|
92 | if let Some(b) = self.pairs.get(&(anc, desc)) { | |||
|
93 | *b | |||
|
94 | } else { | |||
|
95 | let b = (self.inner)(anc, desc); | |||
|
96 | self.pairs.insert((anc, desc), b); | |||
|
97 | b | |||
|
98 | } | |||
|
99 | } | |||
|
100 | } | |||
|
101 | } | |||
|
102 | ||||
67 | /// Same as mercurial.copies._combine_changeset_copies, but in Rust. |
|
103 | /// Same as mercurial.copies._combine_changeset_copies, but in Rust. | |
68 | /// |
|
104 | /// | |
69 | /// Arguments are: |
|
105 | /// Arguments are: | |
@@ -77,14 +113,15 b' impl ChangedFiles {' | |||||
77 | /// * ChangedFiles |
|
113 | /// * ChangedFiles | |
78 | /// isancestors(low_rev, high_rev): callback to check if a revision is an |
|
114 | /// isancestors(low_rev, high_rev): callback to check if a revision is an | |
79 | /// ancestor of another |
|
115 | /// ancestor of another | |
80 | pub fn combine_changeset_copies( |
|
116 | pub fn combine_changeset_copies<A: Fn(Revision, Revision) -> bool>( | |
81 | revs: Vec<Revision>, |
|
117 | revs: Vec<Revision>, | |
82 | children: HashMap<Revision, Vec<Revision>>, |
|
118 | children: HashMap<Revision, Vec<Revision>>, | |
83 | target_rev: Revision, |
|
119 | target_rev: Revision, | |
84 | rev_info: &impl Fn(Revision) -> RevInfo, |
|
120 | rev_info: &impl Fn(Revision) -> RevInfo, | |
85 | is_ancestor: &impl Fn(Revision, Revision) -> bool, |
|
121 | is_ancestor: &A, | |
86 | ) -> PathCopies { |
|
122 | ) -> PathCopies { | |
87 | let mut all_copies = HashMap::new(); |
|
123 | let mut all_copies = HashMap::new(); | |
|
124 | let mut oracle = AncestorOracle::new(is_ancestor); | |||
88 |
|
125 | |||
89 | for rev in revs { |
|
126 | for rev in revs { | |
90 | // Retrieve data computed in a previous iteration |
|
127 | // Retrieve data computed in a previous iteration | |
@@ -168,7 +205,7 b' pub fn combine_changeset_copies(' | |||||
168 | _ => unreachable!(), |
|
205 | _ => unreachable!(), | |
169 | }; |
|
206 | }; | |
170 | let merged_copies = |
|
207 | let merged_copies = | |
171 |
merge_copies_dict(minor, major, &changes, |
|
208 | merge_copies_dict(minor, major, &changes, &mut oracle); | |
172 | all_copies.insert(child, merged_copies); |
|
209 | all_copies.insert(child, merged_copies); | |
173 | } |
|
210 | } | |
174 | }; |
|
211 | }; | |
@@ -194,11 +231,11 b' pub fn combine_changeset_copies(' | |||||
194 | /// In case of conflict, value from "major" will be picked, unless in some |
|
231 | /// In case of conflict, value from "major" will be picked, unless in some | |
195 | /// cases. See inline documentation for details. |
|
232 | /// cases. See inline documentation for details. | |
196 | #[allow(clippy::if_same_then_else)] |
|
233 | #[allow(clippy::if_same_then_else)] | |
197 | fn merge_copies_dict( |
|
234 | fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( | |
198 | minor: TimeStampedPathCopies, |
|
235 | minor: TimeStampedPathCopies, | |
199 | major: TimeStampedPathCopies, |
|
236 | major: TimeStampedPathCopies, | |
200 | changes: &ChangedFiles, |
|
237 | changes: &ChangedFiles, | |
201 | is_ancestor: &impl Fn(Revision, Revision) -> bool, |
|
238 | oracle: &mut AncestorOracle<A>, | |
202 | ) -> TimeStampedPathCopies { |
|
239 | ) -> TimeStampedPathCopies { | |
203 | if minor.is_empty() { |
|
240 | if minor.is_empty() { | |
204 | return major; |
|
241 | return major; | |
@@ -244,7 +281,8 b' fn merge_copies_dict(' | |||||
244 | // If the two entry are identical, no need to do |
|
281 | // If the two entry are identical, no need to do | |
245 | // anything (but diff should not have yield them) |
|
282 | // anything (but diff should not have yield them) | |
246 | unreachable!(); |
|
283 | unreachable!(); | |
247 |
} else if is_ancestor(src_major.rev, src_minor.rev) |
|
284 | } else if oracle.is_ancestor(src_major.rev, src_minor.rev) | |
|
285 | { | |||
248 | pick_minor(); |
|
286 | pick_minor(); | |
249 | } else { |
|
287 | } else { | |
250 | pick_major(); |
|
288 | pick_major(); | |
@@ -271,7 +309,7 b' fn merge_copies_dict(' | |||||
271 | // each side might conflict. The major side will win such |
|
309 | // each side might conflict. The major side will win such | |
272 | // conflict. |
|
310 | // conflict. | |
273 | pick_major(); |
|
311 | pick_major(); | |
274 | } else if is_ancestor(src_major.rev, src_minor.rev) { |
|
312 | } else if oracle.is_ancestor(src_major.rev, src_minor.rev) { | |
275 | // If the minor side is strictly newer than the major side, |
|
313 | // If the minor side is strictly newer than the major side, | |
276 | // it should be kept. |
|
314 | // it should be kept. | |
277 | pick_minor(); |
|
315 | pick_minor(); | |
@@ -279,7 +317,7 b' fn merge_copies_dict(' | |||||
279 | // without any special case, the "major" value win other |
|
317 | // without any special case, the "major" value win other | |
280 | // the "minor" one. |
|
318 | // the "minor" one. | |
281 | pick_major(); |
|
319 | pick_major(); | |
282 | } else if is_ancestor(src_minor.rev, src_major.rev) { |
|
320 | } else if oracle.is_ancestor(src_minor.rev, src_major.rev) { | |
283 | // the "major" rev is a direct ancestors of "minor", any |
|
321 | // the "major" rev is a direct ancestors of "minor", any | |
284 | // different value should overwrite |
|
322 | // different value should overwrite | |
285 | pick_major(); |
|
323 | pick_major(); |
General Comments 0
You need to be logged in to leave comments.
Login now