##// END OF EJS Templates
rust: stop putting NULL_REVISION in MissingAncestors.bases...
Georges Racinet -
r41865:97743297 default
parent child Browse files
Show More
@@ -1,767 +1,766
1 // ancestors.rs
1 // ancestors.rs
2 //
2 //
3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Rust versions of generic DAG ancestors algorithms for Mercurial
8 //! Rust versions of generic DAG ancestors algorithms for Mercurial
9
9
10 use super::{Graph, GraphError, Revision, NULL_REVISION};
10 use super::{Graph, GraphError, Revision, NULL_REVISION};
11 use std::cmp::max;
11 use std::cmp::max;
12 use std::collections::{BinaryHeap, HashSet};
12 use std::collections::{BinaryHeap, HashSet};
13 use crate::dagops;
13 use crate::dagops;
14
14
15 /// Iterator over the ancestors of a given list of revisions
15 /// Iterator over the ancestors of a given list of revisions
16 /// This is a generic type, defined and implemented for any Graph, so that
16 /// This is a generic type, defined and implemented for any Graph, so that
17 /// it's easy to
17 /// it's easy to
18 ///
18 ///
19 /// - unit test in pure Rust
19 /// - unit test in pure Rust
20 /// - bind to main Mercurial code, potentially in several ways and have these
20 /// - bind to main Mercurial code, potentially in several ways and have these
21 /// bindings evolve over time
21 /// bindings evolve over time
22 pub struct AncestorsIterator<G: Graph> {
22 pub struct AncestorsIterator<G: Graph> {
23 graph: G,
23 graph: G,
24 visit: BinaryHeap<Revision>,
24 visit: BinaryHeap<Revision>,
25 seen: HashSet<Revision>,
25 seen: HashSet<Revision>,
26 stoprev: Revision,
26 stoprev: Revision,
27 }
27 }
28
28
29 /// Lazy ancestors set, backed by AncestorsIterator
29 /// Lazy ancestors set, backed by AncestorsIterator
30 pub struct LazyAncestors<G: Graph + Clone> {
30 pub struct LazyAncestors<G: Graph + Clone> {
31 graph: G,
31 graph: G,
32 containsiter: AncestorsIterator<G>,
32 containsiter: AncestorsIterator<G>,
33 initrevs: Vec<Revision>,
33 initrevs: Vec<Revision>,
34 stoprev: Revision,
34 stoprev: Revision,
35 inclusive: bool,
35 inclusive: bool,
36 }
36 }
37
37
38 pub struct MissingAncestors<G: Graph> {
38 pub struct MissingAncestors<G: Graph> {
39 graph: G,
39 graph: G,
40 bases: HashSet<Revision>,
40 bases: HashSet<Revision>,
41 }
41 }
42
42
43 impl<G: Graph> AncestorsIterator<G> {
43 impl<G: Graph> AncestorsIterator<G> {
44 /// Constructor.
44 /// Constructor.
45 ///
45 ///
46 /// if `inclusive` is true, then the init revisions are emitted in
46 /// if `inclusive` is true, then the init revisions are emitted in
47 /// particular, otherwise iteration starts from their parents.
47 /// particular, otherwise iteration starts from their parents.
48 pub fn new(
48 pub fn new(
49 graph: G,
49 graph: G,
50 initrevs: impl IntoIterator<Item = Revision>,
50 initrevs: impl IntoIterator<Item = Revision>,
51 stoprev: Revision,
51 stoprev: Revision,
52 inclusive: bool,
52 inclusive: bool,
53 ) -> Result<Self, GraphError> {
53 ) -> Result<Self, GraphError> {
54 let filtered_initrevs = initrevs.into_iter().filter(|&r| r >= stoprev);
54 let filtered_initrevs = initrevs.into_iter().filter(|&r| r >= stoprev);
55 if inclusive {
55 if inclusive {
56 let visit: BinaryHeap<Revision> = filtered_initrevs.collect();
56 let visit: BinaryHeap<Revision> = filtered_initrevs.collect();
57 let seen = visit.iter().map(|&x| x).collect();
57 let seen = visit.iter().map(|&x| x).collect();
58 return Ok(AncestorsIterator {
58 return Ok(AncestorsIterator {
59 visit: visit,
59 visit: visit,
60 seen: seen,
60 seen: seen,
61 stoprev: stoprev,
61 stoprev: stoprev,
62 graph: graph,
62 graph: graph,
63 });
63 });
64 }
64 }
65 let mut this = AncestorsIterator {
65 let mut this = AncestorsIterator {
66 visit: BinaryHeap::new(),
66 visit: BinaryHeap::new(),
67 seen: HashSet::new(),
67 seen: HashSet::new(),
68 stoprev: stoprev,
68 stoprev: stoprev,
69 graph: graph,
69 graph: graph,
70 };
70 };
71 this.seen.insert(NULL_REVISION);
71 this.seen.insert(NULL_REVISION);
72 for rev in filtered_initrevs {
72 for rev in filtered_initrevs {
73 for parent in this.graph.parents(rev)?.iter().cloned() {
73 for parent in this.graph.parents(rev)?.iter().cloned() {
74 this.conditionally_push_rev(parent);
74 this.conditionally_push_rev(parent);
75 }
75 }
76 }
76 }
77 Ok(this)
77 Ok(this)
78 }
78 }
79
79
80 #[inline]
80 #[inline]
81 fn conditionally_push_rev(&mut self, rev: Revision) {
81 fn conditionally_push_rev(&mut self, rev: Revision) {
82 if self.stoprev <= rev && self.seen.insert(rev) {
82 if self.stoprev <= rev && self.seen.insert(rev) {
83 self.visit.push(rev);
83 self.visit.push(rev);
84 }
84 }
85 }
85 }
86
86
87 /// Consumes partially the iterator to tell if the given target
87 /// Consumes partially the iterator to tell if the given target
88 /// revision
88 /// revision
89 /// is in the ancestors it emits.
89 /// is in the ancestors it emits.
90 /// This is meant for iterators actually dedicated to that kind of
90 /// This is meant for iterators actually dedicated to that kind of
91 /// purpose
91 /// purpose
92 pub fn contains(&mut self, target: Revision) -> Result<bool, GraphError> {
92 pub fn contains(&mut self, target: Revision) -> Result<bool, GraphError> {
93 if self.seen.contains(&target) && target != NULL_REVISION {
93 if self.seen.contains(&target) && target != NULL_REVISION {
94 return Ok(true);
94 return Ok(true);
95 }
95 }
96 for item in self {
96 for item in self {
97 let rev = item?;
97 let rev = item?;
98 if rev == target {
98 if rev == target {
99 return Ok(true);
99 return Ok(true);
100 }
100 }
101 if rev < target {
101 if rev < target {
102 return Ok(false);
102 return Ok(false);
103 }
103 }
104 }
104 }
105 Ok(false)
105 Ok(false)
106 }
106 }
107
107
108 pub fn peek(&self) -> Option<Revision> {
108 pub fn peek(&self) -> Option<Revision> {
109 self.visit.peek().map(|&r| r)
109 self.visit.peek().map(|&r| r)
110 }
110 }
111
111
112 /// Tell if the iterator is about an empty set
112 /// Tell if the iterator is about an empty set
113 ///
113 ///
114 /// The result does not depend whether the iterator has been consumed
114 /// The result does not depend whether the iterator has been consumed
115 /// or not.
115 /// or not.
116 /// This is mostly meant for iterators backing a lazy ancestors set
116 /// This is mostly meant for iterators backing a lazy ancestors set
117 pub fn is_empty(&self) -> bool {
117 pub fn is_empty(&self) -> bool {
118 if self.visit.len() > 0 {
118 if self.visit.len() > 0 {
119 return false;
119 return false;
120 }
120 }
121 if self.seen.len() > 1 {
121 if self.seen.len() > 1 {
122 return false;
122 return false;
123 }
123 }
124 // at this point, the seen set is at most a singleton.
124 // at this point, the seen set is at most a singleton.
125 // If not `self.inclusive`, it's still possible that it has only
125 // If not `self.inclusive`, it's still possible that it has only
126 // the null revision
126 // the null revision
127 self.seen.is_empty() || self.seen.contains(&NULL_REVISION)
127 self.seen.is_empty() || self.seen.contains(&NULL_REVISION)
128 }
128 }
129 }
129 }
130
130
131 /// Main implementation for the iterator
131 /// Main implementation for the iterator
132 ///
132 ///
133 /// The algorithm is the same as in `_lazyancestorsiter()` from `ancestors.py`
133 /// The algorithm is the same as in `_lazyancestorsiter()` from `ancestors.py`
134 /// with a few non crucial differences:
134 /// with a few non crucial differences:
135 ///
135 ///
136 /// - there's no filtering of invalid parent revisions. Actually, it should be
136 /// - there's no filtering of invalid parent revisions. Actually, it should be
137 /// consistent and more efficient to filter them from the end caller.
137 /// consistent and more efficient to filter them from the end caller.
138 /// - we don't have the optimization for adjacent revisions (i.e., the case
138 /// - we don't have the optimization for adjacent revisions (i.e., the case
139 /// where `p1 == rev - 1`), because it amounts to update the first element of
139 /// where `p1 == rev - 1`), because it amounts to update the first element of
140 /// the heap without sifting, which Rust's BinaryHeap doesn't let us do.
140 /// the heap without sifting, which Rust's BinaryHeap doesn't let us do.
141 /// - we save a few pushes by comparing with `stoprev` before pushing
141 /// - we save a few pushes by comparing with `stoprev` before pushing
142 impl<G: Graph> Iterator for AncestorsIterator<G> {
142 impl<G: Graph> Iterator for AncestorsIterator<G> {
143 type Item = Result<Revision, GraphError>;
143 type Item = Result<Revision, GraphError>;
144
144
145 fn next(&mut self) -> Option<Self::Item> {
145 fn next(&mut self) -> Option<Self::Item> {
146 let current = match self.visit.peek() {
146 let current = match self.visit.peek() {
147 None => {
147 None => {
148 return None;
148 return None;
149 }
149 }
150 Some(c) => *c,
150 Some(c) => *c,
151 };
151 };
152 let [p1, p2] = match self.graph.parents(current) {
152 let [p1, p2] = match self.graph.parents(current) {
153 Ok(ps) => ps,
153 Ok(ps) => ps,
154 Err(e) => return Some(Err(e)),
154 Err(e) => return Some(Err(e)),
155 };
155 };
156 if p1 < self.stoprev || !self.seen.insert(p1) {
156 if p1 < self.stoprev || !self.seen.insert(p1) {
157 self.visit.pop();
157 self.visit.pop();
158 } else {
158 } else {
159 *(self.visit.peek_mut().unwrap()) = p1;
159 *(self.visit.peek_mut().unwrap()) = p1;
160 };
160 };
161
161
162 self.conditionally_push_rev(p2);
162 self.conditionally_push_rev(p2);
163 Some(Ok(current))
163 Some(Ok(current))
164 }
164 }
165 }
165 }
166
166
167 impl<G: Graph + Clone> LazyAncestors<G> {
167 impl<G: Graph + Clone> LazyAncestors<G> {
168 pub fn new(
168 pub fn new(
169 graph: G,
169 graph: G,
170 initrevs: impl IntoIterator<Item = Revision>,
170 initrevs: impl IntoIterator<Item = Revision>,
171 stoprev: Revision,
171 stoprev: Revision,
172 inclusive: bool,
172 inclusive: bool,
173 ) -> Result<Self, GraphError> {
173 ) -> Result<Self, GraphError> {
174 let v: Vec<Revision> = initrevs.into_iter().collect();
174 let v: Vec<Revision> = initrevs.into_iter().collect();
175 Ok(LazyAncestors {
175 Ok(LazyAncestors {
176 graph: graph.clone(),
176 graph: graph.clone(),
177 containsiter: AncestorsIterator::new(
177 containsiter: AncestorsIterator::new(
178 graph,
178 graph,
179 v.iter().cloned(),
179 v.iter().cloned(),
180 stoprev,
180 stoprev,
181 inclusive,
181 inclusive,
182 )?,
182 )?,
183 initrevs: v,
183 initrevs: v,
184 stoprev: stoprev,
184 stoprev: stoprev,
185 inclusive: inclusive,
185 inclusive: inclusive,
186 })
186 })
187 }
187 }
188
188
189 pub fn contains(&mut self, rev: Revision) -> Result<bool, GraphError> {
189 pub fn contains(&mut self, rev: Revision) -> Result<bool, GraphError> {
190 self.containsiter.contains(rev)
190 self.containsiter.contains(rev)
191 }
191 }
192
192
193 pub fn is_empty(&self) -> bool {
193 pub fn is_empty(&self) -> bool {
194 self.containsiter.is_empty()
194 self.containsiter.is_empty()
195 }
195 }
196
196
197 pub fn iter(&self) -> AncestorsIterator<G> {
197 pub fn iter(&self) -> AncestorsIterator<G> {
198 // the arguments being the same as for self.containsiter, we know
198 // the arguments being the same as for self.containsiter, we know
199 // for sure that AncestorsIterator constructor can't fail
199 // for sure that AncestorsIterator constructor can't fail
200 AncestorsIterator::new(
200 AncestorsIterator::new(
201 self.graph.clone(),
201 self.graph.clone(),
202 self.initrevs.iter().cloned(),
202 self.initrevs.iter().cloned(),
203 self.stoprev,
203 self.stoprev,
204 self.inclusive,
204 self.inclusive,
205 )
205 )
206 .unwrap()
206 .unwrap()
207 }
207 }
208 }
208 }
209
209
210 impl<G: Graph> MissingAncestors<G> {
210 impl<G: Graph> MissingAncestors<G> {
211 pub fn new(graph: G, bases: impl IntoIterator<Item = Revision>) -> Self {
211 pub fn new(graph: G, bases: impl IntoIterator<Item = Revision>) -> Self {
212 let mut bases: HashSet<Revision> = bases.into_iter().collect();
212 MissingAncestors { graph: graph, bases: bases.into_iter().collect() }
213 if bases.is_empty() {
214 bases.insert(NULL_REVISION);
215 }
216 MissingAncestors { graph, bases }
217 }
213 }
218
214
219 pub fn has_bases(&self) -> bool {
215 pub fn has_bases(&self) -> bool {
220 self.bases.iter().any(|&b| b != NULL_REVISION)
216 !self.bases.is_empty()
221 }
217 }
222
218
223 /// Return a reference to current bases.
219 /// Return a reference to current bases.
224 ///
220 ///
225 /// This is useful in unit tests, but also setdiscovery.py does
221 /// This is useful in unit tests, but also setdiscovery.py does
226 /// read the bases attribute of a ancestor.missingancestors instance.
222 /// read the bases attribute of a ancestor.missingancestors instance.
227 pub fn get_bases<'a>(&'a self) -> &'a HashSet<Revision> {
223 pub fn get_bases<'a>(&'a self) -> &'a HashSet<Revision> {
228 &self.bases
224 &self.bases
229 }
225 }
230
226
231 /// Computes the relative heads of current bases.
227 /// Computes the relative heads of current bases.
232 ///
228 ///
233 /// The object is still usable after this.
229 /// The object is still usable after this.
234 pub fn bases_heads(&self) -> Result<HashSet<Revision>, GraphError> {
230 pub fn bases_heads(&self) -> Result<HashSet<Revision>, GraphError> {
235 dagops::heads(&self.graph, self.bases.iter())
231 dagops::heads(&self.graph, self.bases.iter())
236 }
232 }
237
233
238 /// Consumes the object and returns the relative heads of its bases.
234 /// Consumes the object and returns the relative heads of its bases.
239 pub fn into_bases_heads(mut self) -> Result<HashSet<Revision>, GraphError> {
235 pub fn into_bases_heads(mut self) -> Result<HashSet<Revision>, GraphError> {
240 dagops::retain_heads(&self.graph, &mut self.bases)?;
236 dagops::retain_heads(&self.graph, &mut self.bases)?;
241 Ok(self.bases)
237 Ok(self.bases)
242 }
238 }
243
239
244 pub fn add_bases(
240 pub fn add_bases(
245 &mut self,
241 &mut self,
246 new_bases: impl IntoIterator<Item = Revision>,
242 new_bases: impl IntoIterator<Item = Revision>,
247 ) {
243 ) {
248 self.bases.extend(new_bases);
244 self.bases
245 .extend(new_bases.into_iter().filter(|&rev| rev != NULL_REVISION));
249 }
246 }
250
247
251 /// Remove all ancestors of self.bases from the revs set (in place)
248 /// Remove all ancestors of self.bases from the revs set (in place)
252 pub fn remove_ancestors_from(
249 pub fn remove_ancestors_from(
253 &mut self,
250 &mut self,
254 revs: &mut HashSet<Revision>,
251 revs: &mut HashSet<Revision>,
255 ) -> Result<(), GraphError> {
252 ) -> Result<(), GraphError> {
256 revs.retain(|r| !self.bases.contains(r));
253 revs.retain(|r| !self.bases.contains(r));
257 // the null revision is always an ancestor
254 // the null revision is always an ancestor. Logically speaking
255 // it's debatable in case bases is empty, but the Python
256 // implementation always adds NULL_REVISION to bases, making it
257 // unconditionnally true.
258 revs.remove(&NULL_REVISION);
258 revs.remove(&NULL_REVISION);
259 if revs.is_empty() {
259 if revs.is_empty() {
260 return Ok(());
260 return Ok(());
261 }
261 }
262 // anything in revs > start is definitely not an ancestor of bases
262 // anything in revs > start is definitely not an ancestor of bases
263 // revs <= start need to be investigated
263 // revs <= start need to be investigated
264 // TODO optim: if a missingancestors is to be used several times,
264 // TODO optim: if a missingancestors is to be used several times,
265 // we shouldn't need to iterate each time on bases
265 // we shouldn't need to iterate each time on bases
266 let start = match self.bases.iter().cloned().max() {
266 let start = match self.bases.iter().cloned().max() {
267 Some(m) => m,
267 Some(m) => m,
268 None => {
268 None => { // self.bases is empty
269 // bases is empty (shouldn't happen, but let's be safe)
270 return Ok(());
269 return Ok(());
271 }
270 }
272 };
271 };
273 // whatever happens, we'll keep at least keepcount of them
272 // whatever happens, we'll keep at least keepcount of them
274 // knowing this gives us a earlier stop condition than
273 // knowing this gives us a earlier stop condition than
275 // going all the way to the root
274 // going all the way to the root
276 let keepcount = revs.iter().filter(|r| **r > start).count();
275 let keepcount = revs.iter().filter(|r| **r > start).count();
277
276
278 let mut curr = start;
277 let mut curr = start;
279 while curr != NULL_REVISION && revs.len() > keepcount {
278 while curr != NULL_REVISION && revs.len() > keepcount {
280 if self.bases.contains(&curr) {
279 if self.bases.contains(&curr) {
281 revs.remove(&curr);
280 revs.remove(&curr);
282 self.add_parents(curr)?;
281 self.add_parents(curr)?;
283 }
282 }
284 curr -= 1;
283 curr -= 1;
285 }
284 }
286 Ok(())
285 Ok(())
287 }
286 }
288
287
289 /// Add rev's parents to self.bases
288 /// Add rev's parents to self.bases
290 #[inline]
289 #[inline]
291 fn add_parents(&mut self, rev: Revision) -> Result<(), GraphError> {
290 fn add_parents(&mut self, rev: Revision) -> Result<(), GraphError> {
292 // No need to bother the set with inserting NULL_REVISION over and
291 // No need to bother the set with inserting NULL_REVISION over and
293 // over
292 // over
294 for p in self.graph.parents(rev)?.iter().cloned() {
293 for p in self.graph.parents(rev)?.iter().cloned() {
295 if p != NULL_REVISION {
294 if p != NULL_REVISION {
296 self.bases.insert(p);
295 self.bases.insert(p);
297 }
296 }
298 }
297 }
299 Ok(())
298 Ok(())
300 }
299 }
301
300
302 /// Return all the ancestors of revs that are not ancestors of self.bases
301 /// Return all the ancestors of revs that are not ancestors of self.bases
303 ///
302 ///
304 /// This may include elements from revs.
303 /// This may include elements from revs.
305 ///
304 ///
306 /// Equivalent to the revset (::revs - ::self.bases). Revs are returned in
305 /// Equivalent to the revset (::revs - ::self.bases). Revs are returned in
307 /// revision number order, which is a topological order.
306 /// revision number order, which is a topological order.
308 pub fn missing_ancestors(
307 pub fn missing_ancestors(
309 &mut self,
308 &mut self,
310 revs: impl IntoIterator<Item = Revision>,
309 revs: impl IntoIterator<Item = Revision>,
311 ) -> Result<Vec<Revision>, GraphError> {
310 ) -> Result<Vec<Revision>, GraphError> {
312 // just for convenience and comparison with Python version
311 // just for convenience and comparison with Python version
313 let bases_visit = &mut self.bases;
312 let bases_visit = &mut self.bases;
314 let mut revs: HashSet<Revision> = revs
313 let mut revs: HashSet<Revision> = revs
315 .into_iter()
314 .into_iter()
316 .filter(|r| !bases_visit.contains(r))
315 .filter(|r| !bases_visit.contains(r))
317 .collect();
316 .collect();
318 let revs_visit = &mut revs;
317 let revs_visit = &mut revs;
319 let mut both_visit: HashSet<Revision> =
318 let mut both_visit: HashSet<Revision> =
320 revs_visit.intersection(&bases_visit).cloned().collect();
319 revs_visit.intersection(&bases_visit).cloned().collect();
321 if revs_visit.is_empty() {
320 if revs_visit.is_empty() {
322 return Ok(Vec::new());
321 return Ok(Vec::new());
323 }
322 }
324
323
325 let max_bases =
324 let max_bases =
326 bases_visit.iter().cloned().max().unwrap_or(NULL_REVISION);
325 bases_visit.iter().cloned().max().unwrap_or(NULL_REVISION);
327 let max_revs =
326 let max_revs =
328 revs_visit.iter().cloned().max().unwrap_or(NULL_REVISION);
327 revs_visit.iter().cloned().max().unwrap_or(NULL_REVISION);
329 let start = max(max_bases, max_revs);
328 let start = max(max_bases, max_revs);
330
329
331 // TODO heuristics for with_capacity()?
330 // TODO heuristics for with_capacity()?
332 let mut missing: Vec<Revision> = Vec::new();
331 let mut missing: Vec<Revision> = Vec::new();
333 for curr in (0..=start).rev() {
332 for curr in (0..=start).rev() {
334 if revs_visit.is_empty() {
333 if revs_visit.is_empty() {
335 break;
334 break;
336 }
335 }
337 if both_visit.remove(&curr) {
336 if both_visit.remove(&curr) {
338 // curr's parents might have made it into revs_visit through
337 // curr's parents might have made it into revs_visit through
339 // another path
338 // another path
340 for p in self.graph.parents(curr)?.iter().cloned() {
339 for p in self.graph.parents(curr)?.iter().cloned() {
341 if p == NULL_REVISION {
340 if p == NULL_REVISION {
342 continue;
341 continue;
343 }
342 }
344 revs_visit.remove(&p);
343 revs_visit.remove(&p);
345 bases_visit.insert(p);
344 bases_visit.insert(p);
346 both_visit.insert(p);
345 both_visit.insert(p);
347 }
346 }
348 } else if revs_visit.remove(&curr) {
347 } else if revs_visit.remove(&curr) {
349 missing.push(curr);
348 missing.push(curr);
350 for p in self.graph.parents(curr)?.iter().cloned() {
349 for p in self.graph.parents(curr)?.iter().cloned() {
351 if p == NULL_REVISION {
350 if p == NULL_REVISION {
352 continue;
351 continue;
353 }
352 }
354 if bases_visit.contains(&p) {
353 if bases_visit.contains(&p) {
355 // p is already known to be an ancestor of revs_visit
354 // p is already known to be an ancestor of revs_visit
356 revs_visit.remove(&p);
355 revs_visit.remove(&p);
357 both_visit.insert(p);
356 both_visit.insert(p);
358 } else if both_visit.contains(&p) {
357 } else if both_visit.contains(&p) {
359 // p should have been in bases_visit
358 // p should have been in bases_visit
360 revs_visit.remove(&p);
359 revs_visit.remove(&p);
361 bases_visit.insert(p);
360 bases_visit.insert(p);
362 } else {
361 } else {
363 // visit later
362 // visit later
364 revs_visit.insert(p);
363 revs_visit.insert(p);
365 }
364 }
366 }
365 }
367 } else if bases_visit.contains(&curr) {
366 } else if bases_visit.contains(&curr) {
368 for p in self.graph.parents(curr)?.iter().cloned() {
367 for p in self.graph.parents(curr)?.iter().cloned() {
369 if p == NULL_REVISION {
368 if p == NULL_REVISION {
370 continue;
369 continue;
371 }
370 }
372 if revs_visit.remove(&p) || both_visit.contains(&p) {
371 if revs_visit.remove(&p) || both_visit.contains(&p) {
373 // p is an ancestor of bases_visit, and is implicitly
372 // p is an ancestor of bases_visit, and is implicitly
374 // in revs_visit, which means p is ::revs & ::bases.
373 // in revs_visit, which means p is ::revs & ::bases.
375 bases_visit.insert(p);
374 bases_visit.insert(p);
376 both_visit.insert(p);
375 both_visit.insert(p);
377 } else {
376 } else {
378 bases_visit.insert(p);
377 bases_visit.insert(p);
379 }
378 }
380 }
379 }
381 }
380 }
382 }
381 }
383 missing.reverse();
382 missing.reverse();
384 Ok(missing)
383 Ok(missing)
385 }
384 }
386 }
385 }
387
386
388 #[cfg(test)]
387 #[cfg(test)]
389 mod tests {
388 mod tests {
390
389
391 use super::*;
390 use super::*;
392 use crate::testing::{SampleGraph, VecGraph};
391 use crate::testing::{SampleGraph, VecGraph};
393 use std::iter::FromIterator;
392 use std::iter::FromIterator;
394
393
395 fn list_ancestors<G: Graph>(
394 fn list_ancestors<G: Graph>(
396 graph: G,
395 graph: G,
397 initrevs: Vec<Revision>,
396 initrevs: Vec<Revision>,
398 stoprev: Revision,
397 stoprev: Revision,
399 inclusive: bool,
398 inclusive: bool,
400 ) -> Vec<Revision> {
399 ) -> Vec<Revision> {
401 AncestorsIterator::new(graph, initrevs, stoprev, inclusive)
400 AncestorsIterator::new(graph, initrevs, stoprev, inclusive)
402 .unwrap()
401 .unwrap()
403 .map(|res| res.unwrap())
402 .map(|res| res.unwrap())
404 .collect()
403 .collect()
405 }
404 }
406
405
407 #[test]
406 #[test]
408 /// Same tests as test-ancestor.py, without membership
407 /// Same tests as test-ancestor.py, without membership
409 /// (see also test-ancestor.py.out)
408 /// (see also test-ancestor.py.out)
410 fn test_list_ancestor() {
409 fn test_list_ancestor() {
411 assert_eq!(list_ancestors(SampleGraph, vec![], 0, false), vec![]);
410 assert_eq!(list_ancestors(SampleGraph, vec![], 0, false), vec![]);
412 assert_eq!(
411 assert_eq!(
413 list_ancestors(SampleGraph, vec![11, 13], 0, false),
412 list_ancestors(SampleGraph, vec![11, 13], 0, false),
414 vec![8, 7, 4, 3, 2, 1, 0]
413 vec![8, 7, 4, 3, 2, 1, 0]
415 );
414 );
416 assert_eq!(
415 assert_eq!(
417 list_ancestors(SampleGraph, vec![1, 3], 0, false),
416 list_ancestors(SampleGraph, vec![1, 3], 0, false),
418 vec![1, 0]
417 vec![1, 0]
419 );
418 );
420 assert_eq!(
419 assert_eq!(
421 list_ancestors(SampleGraph, vec![11, 13], 0, true),
420 list_ancestors(SampleGraph, vec![11, 13], 0, true),
422 vec![13, 11, 8, 7, 4, 3, 2, 1, 0]
421 vec![13, 11, 8, 7, 4, 3, 2, 1, 0]
423 );
422 );
424 assert_eq!(
423 assert_eq!(
425 list_ancestors(SampleGraph, vec![11, 13], 6, false),
424 list_ancestors(SampleGraph, vec![11, 13], 6, false),
426 vec![8, 7]
425 vec![8, 7]
427 );
426 );
428 assert_eq!(
427 assert_eq!(
429 list_ancestors(SampleGraph, vec![11, 13], 6, true),
428 list_ancestors(SampleGraph, vec![11, 13], 6, true),
430 vec![13, 11, 8, 7]
429 vec![13, 11, 8, 7]
431 );
430 );
432 assert_eq!(
431 assert_eq!(
433 list_ancestors(SampleGraph, vec![11, 13], 11, true),
432 list_ancestors(SampleGraph, vec![11, 13], 11, true),
434 vec![13, 11]
433 vec![13, 11]
435 );
434 );
436 assert_eq!(
435 assert_eq!(
437 list_ancestors(SampleGraph, vec![11, 13], 12, true),
436 list_ancestors(SampleGraph, vec![11, 13], 12, true),
438 vec![13]
437 vec![13]
439 );
438 );
440 assert_eq!(
439 assert_eq!(
441 list_ancestors(SampleGraph, vec![10, 1], 0, true),
440 list_ancestors(SampleGraph, vec![10, 1], 0, true),
442 vec![10, 5, 4, 2, 1, 0]
441 vec![10, 5, 4, 2, 1, 0]
443 );
442 );
444 }
443 }
445
444
446 #[test]
445 #[test]
447 /// Corner case that's not directly in test-ancestors.py, but
446 /// Corner case that's not directly in test-ancestors.py, but
448 /// that happens quite often, as demonstrated by running the whole
447 /// that happens quite often, as demonstrated by running the whole
449 /// suite.
448 /// suite.
450 /// For instance, run tests/test-obsolete-checkheads.t
449 /// For instance, run tests/test-obsolete-checkheads.t
451 fn test_nullrev_input() {
450 fn test_nullrev_input() {
452 let mut iter =
451 let mut iter =
453 AncestorsIterator::new(SampleGraph, vec![-1], 0, false).unwrap();
452 AncestorsIterator::new(SampleGraph, vec![-1], 0, false).unwrap();
454 assert_eq!(iter.next(), None)
453 assert_eq!(iter.next(), None)
455 }
454 }
456
455
457 #[test]
456 #[test]
458 fn test_contains() {
457 fn test_contains() {
459 let mut lazy =
458 let mut lazy =
460 AncestorsIterator::new(SampleGraph, vec![10, 1], 0, true).unwrap();
459 AncestorsIterator::new(SampleGraph, vec![10, 1], 0, true).unwrap();
461 assert!(lazy.contains(1).unwrap());
460 assert!(lazy.contains(1).unwrap());
462 assert!(!lazy.contains(3).unwrap());
461 assert!(!lazy.contains(3).unwrap());
463
462
464 let mut lazy =
463 let mut lazy =
465 AncestorsIterator::new(SampleGraph, vec![0], 0, false).unwrap();
464 AncestorsIterator::new(SampleGraph, vec![0], 0, false).unwrap();
466 assert!(!lazy.contains(NULL_REVISION).unwrap());
465 assert!(!lazy.contains(NULL_REVISION).unwrap());
467 }
466 }
468
467
469 #[test]
468 #[test]
470 fn test_peek() {
469 fn test_peek() {
471 let mut iter =
470 let mut iter =
472 AncestorsIterator::new(SampleGraph, vec![10], 0, true).unwrap();
471 AncestorsIterator::new(SampleGraph, vec![10], 0, true).unwrap();
473 // peek() gives us the next value
472 // peek() gives us the next value
474 assert_eq!(iter.peek(), Some(10));
473 assert_eq!(iter.peek(), Some(10));
475 // but it's not been consumed
474 // but it's not been consumed
476 assert_eq!(iter.next(), Some(Ok(10)));
475 assert_eq!(iter.next(), Some(Ok(10)));
477 // and iteration resumes normally
476 // and iteration resumes normally
478 assert_eq!(iter.next(), Some(Ok(5)));
477 assert_eq!(iter.next(), Some(Ok(5)));
479
478
480 // let's drain the iterator to test peek() at the end
479 // let's drain the iterator to test peek() at the end
481 while iter.next().is_some() {}
480 while iter.next().is_some() {}
482 assert_eq!(iter.peek(), None);
481 assert_eq!(iter.peek(), None);
483 }
482 }
484
483
485 #[test]
484 #[test]
486 fn test_empty() {
485 fn test_empty() {
487 let mut iter =
486 let mut iter =
488 AncestorsIterator::new(SampleGraph, vec![10], 0, true).unwrap();
487 AncestorsIterator::new(SampleGraph, vec![10], 0, true).unwrap();
489 assert!(!iter.is_empty());
488 assert!(!iter.is_empty());
490 while iter.next().is_some() {}
489 while iter.next().is_some() {}
491 assert!(!iter.is_empty());
490 assert!(!iter.is_empty());
492
491
493 let iter =
492 let iter =
494 AncestorsIterator::new(SampleGraph, vec![], 0, true).unwrap();
493 AncestorsIterator::new(SampleGraph, vec![], 0, true).unwrap();
495 assert!(iter.is_empty());
494 assert!(iter.is_empty());
496
495
497 // case where iter.seen == {NULL_REVISION}
496 // case where iter.seen == {NULL_REVISION}
498 let iter =
497 let iter =
499 AncestorsIterator::new(SampleGraph, vec![0], 0, false).unwrap();
498 AncestorsIterator::new(SampleGraph, vec![0], 0, false).unwrap();
500 assert!(iter.is_empty());
499 assert!(iter.is_empty());
501 }
500 }
502
501
503 /// A corrupted Graph, supporting error handling tests
502 /// A corrupted Graph, supporting error handling tests
504 #[derive(Clone, Debug)]
503 #[derive(Clone, Debug)]
505 struct Corrupted;
504 struct Corrupted;
506
505
507 impl Graph for Corrupted {
506 impl Graph for Corrupted {
508 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
507 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
509 match rev {
508 match rev {
510 1 => Ok([0, -1]),
509 1 => Ok([0, -1]),
511 r => Err(GraphError::ParentOutOfRange(r)),
510 r => Err(GraphError::ParentOutOfRange(r)),
512 }
511 }
513 }
512 }
514 }
513 }
515
514
516 #[test]
515 #[test]
517 fn test_initrev_out_of_range() {
516 fn test_initrev_out_of_range() {
518 // inclusive=false looks up initrev's parents right away
517 // inclusive=false looks up initrev's parents right away
519 match AncestorsIterator::new(SampleGraph, vec![25], 0, false) {
518 match AncestorsIterator::new(SampleGraph, vec![25], 0, false) {
520 Ok(_) => panic!("Should have been ParentOutOfRange"),
519 Ok(_) => panic!("Should have been ParentOutOfRange"),
521 Err(e) => assert_eq!(e, GraphError::ParentOutOfRange(25)),
520 Err(e) => assert_eq!(e, GraphError::ParentOutOfRange(25)),
522 }
521 }
523 }
522 }
524
523
525 #[test]
524 #[test]
526 fn test_next_out_of_range() {
525 fn test_next_out_of_range() {
527 // inclusive=false looks up initrev's parents right away
526 // inclusive=false looks up initrev's parents right away
528 let mut iter =
527 let mut iter =
529 AncestorsIterator::new(Corrupted, vec![1], 0, false).unwrap();
528 AncestorsIterator::new(Corrupted, vec![1], 0, false).unwrap();
530 assert_eq!(iter.next(), Some(Err(GraphError::ParentOutOfRange(0))));
529 assert_eq!(iter.next(), Some(Err(GraphError::ParentOutOfRange(0))));
531 }
530 }
532
531
533 #[test]
532 #[test]
534 fn test_lazy_iter_contains() {
533 fn test_lazy_iter_contains() {
535 let mut lazy =
534 let mut lazy =
536 LazyAncestors::new(SampleGraph, vec![11, 13], 0, false).unwrap();
535 LazyAncestors::new(SampleGraph, vec![11, 13], 0, false).unwrap();
537
536
538 let revs: Vec<Revision> = lazy.iter().map(|r| r.unwrap()).collect();
537 let revs: Vec<Revision> = lazy.iter().map(|r| r.unwrap()).collect();
539 // compare with iterator tests on the same initial revisions
538 // compare with iterator tests on the same initial revisions
540 assert_eq!(revs, vec![8, 7, 4, 3, 2, 1, 0]);
539 assert_eq!(revs, vec![8, 7, 4, 3, 2, 1, 0]);
541
540
542 // contains() results are correct, unaffected by the fact that
541 // contains() results are correct, unaffected by the fact that
543 // we consumed entirely an iterator out of lazy
542 // we consumed entirely an iterator out of lazy
544 assert_eq!(lazy.contains(2), Ok(true));
543 assert_eq!(lazy.contains(2), Ok(true));
545 assert_eq!(lazy.contains(9), Ok(false));
544 assert_eq!(lazy.contains(9), Ok(false));
546 }
545 }
547
546
548 #[test]
547 #[test]
549 fn test_lazy_contains_iter() {
548 fn test_lazy_contains_iter() {
550 let mut lazy =
549 let mut lazy =
551 LazyAncestors::new(SampleGraph, vec![11, 13], 0, false).unwrap(); // reminder: [8, 7, 4, 3, 2, 1, 0]
550 LazyAncestors::new(SampleGraph, vec![11, 13], 0, false).unwrap(); // reminder: [8, 7, 4, 3, 2, 1, 0]
552
551
553 assert_eq!(lazy.contains(2), Ok(true));
552 assert_eq!(lazy.contains(2), Ok(true));
554 assert_eq!(lazy.contains(6), Ok(false));
553 assert_eq!(lazy.contains(6), Ok(false));
555
554
556 // after consumption of 2 by the inner iterator, results stay
555 // after consumption of 2 by the inner iterator, results stay
557 // consistent
556 // consistent
558 assert_eq!(lazy.contains(2), Ok(true));
557 assert_eq!(lazy.contains(2), Ok(true));
559 assert_eq!(lazy.contains(5), Ok(false));
558 assert_eq!(lazy.contains(5), Ok(false));
560
559
561 // iter() still gives us a fresh iterator
560 // iter() still gives us a fresh iterator
562 let revs: Vec<Revision> = lazy.iter().map(|r| r.unwrap()).collect();
561 let revs: Vec<Revision> = lazy.iter().map(|r| r.unwrap()).collect();
563 assert_eq!(revs, vec![8, 7, 4, 3, 2, 1, 0]);
562 assert_eq!(revs, vec![8, 7, 4, 3, 2, 1, 0]);
564 }
563 }
565
564
566 #[test]
565 #[test]
567 /// Test constructor, add/get bases and heads
566 /// Test constructor, add/get bases and heads
568 fn test_missing_bases() -> Result<(), GraphError> {
567 fn test_missing_bases() -> Result<(), GraphError> {
569 let mut missing_ancestors =
568 let mut missing_ancestors =
570 MissingAncestors::new(SampleGraph, [5, 3, 1, 3].iter().cloned());
569 MissingAncestors::new(SampleGraph, [5, 3, 1, 3].iter().cloned());
571 let mut as_vec: Vec<Revision> =
570 let mut as_vec: Vec<Revision> =
572 missing_ancestors.get_bases().iter().cloned().collect();
571 missing_ancestors.get_bases().iter().cloned().collect();
573 as_vec.sort();
572 as_vec.sort();
574 assert_eq!(as_vec, [1, 3, 5]);
573 assert_eq!(as_vec, [1, 3, 5]);
575
574
576 missing_ancestors.add_bases([3, 7, 8].iter().cloned());
575 missing_ancestors.add_bases([3, 7, 8].iter().cloned());
577 as_vec = missing_ancestors.get_bases().iter().cloned().collect();
576 as_vec = missing_ancestors.get_bases().iter().cloned().collect();
578 as_vec.sort();
577 as_vec.sort();
579 assert_eq!(as_vec, [1, 3, 5, 7, 8]);
578 assert_eq!(as_vec, [1, 3, 5, 7, 8]);
580
579
581 as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect();
580 as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect();
582 as_vec.sort();
581 as_vec.sort();
583 assert_eq!(as_vec, [3, 5, 7, 8]);
582 assert_eq!(as_vec, [3, 5, 7, 8]);
584 Ok(())
583 Ok(())
585 }
584 }
586
585
587 fn assert_missing_remove(
586 fn assert_missing_remove(
588 bases: &[Revision],
587 bases: &[Revision],
589 revs: &[Revision],
588 revs: &[Revision],
590 expected: &[Revision],
589 expected: &[Revision],
591 ) {
590 ) {
592 let mut missing_ancestors =
591 let mut missing_ancestors =
593 MissingAncestors::new(SampleGraph, bases.iter().cloned());
592 MissingAncestors::new(SampleGraph, bases.iter().cloned());
594 let mut revset: HashSet<Revision> = revs.iter().cloned().collect();
593 let mut revset: HashSet<Revision> = revs.iter().cloned().collect();
595 missing_ancestors
594 missing_ancestors
596 .remove_ancestors_from(&mut revset)
595 .remove_ancestors_from(&mut revset)
597 .unwrap();
596 .unwrap();
598 let mut as_vec: Vec<Revision> = revset.into_iter().collect();
597 let mut as_vec: Vec<Revision> = revset.into_iter().collect();
599 as_vec.sort();
598 as_vec.sort();
600 assert_eq!(as_vec.as_slice(), expected);
599 assert_eq!(as_vec.as_slice(), expected);
601 }
600 }
602
601
603 #[test]
602 #[test]
604 fn test_missing_remove() {
603 fn test_missing_remove() {
605 assert_missing_remove(
604 assert_missing_remove(
606 &[1, 2, 3, 4, 7],
605 &[1, 2, 3, 4, 7],
607 Vec::from_iter(1..10).as_slice(),
606 Vec::from_iter(1..10).as_slice(),
608 &[5, 6, 8, 9],
607 &[5, 6, 8, 9],
609 );
608 );
610 assert_missing_remove(&[10], &[11, 12, 13, 14], &[11, 12, 13, 14]);
609 assert_missing_remove(&[10], &[11, 12, 13, 14], &[11, 12, 13, 14]);
611 assert_missing_remove(&[7], &[1, 2, 3, 4, 5], &[3, 5]);
610 assert_missing_remove(&[7], &[1, 2, 3, 4, 5], &[3, 5]);
612 }
611 }
613
612
614 fn assert_missing_ancestors(
613 fn assert_missing_ancestors(
615 bases: &[Revision],
614 bases: &[Revision],
616 revs: &[Revision],
615 revs: &[Revision],
617 expected: &[Revision],
616 expected: &[Revision],
618 ) {
617 ) {
619 let mut missing_ancestors =
618 let mut missing_ancestors =
620 MissingAncestors::new(SampleGraph, bases.iter().cloned());
619 MissingAncestors::new(SampleGraph, bases.iter().cloned());
621 let missing = missing_ancestors
620 let missing = missing_ancestors
622 .missing_ancestors(revs.iter().cloned())
621 .missing_ancestors(revs.iter().cloned())
623 .unwrap();
622 .unwrap();
624 assert_eq!(missing.as_slice(), expected);
623 assert_eq!(missing.as_slice(), expected);
625 }
624 }
626
625
627 #[test]
626 #[test]
628 fn test_missing_ancestors() {
627 fn test_missing_ancestors() {
629 // examples taken from test-ancestors.py by having it run
628 // examples taken from test-ancestors.py by having it run
630 // on the same graph (both naive and fast Python algs)
629 // on the same graph (both naive and fast Python algs)
631 assert_missing_ancestors(&[10], &[11], &[3, 7, 11]);
630 assert_missing_ancestors(&[10], &[11], &[3, 7, 11]);
632 assert_missing_ancestors(&[11], &[10], &[5, 10]);
631 assert_missing_ancestors(&[11], &[10], &[5, 10]);
633 assert_missing_ancestors(&[7], &[9, 11], &[3, 6, 9, 11]);
632 assert_missing_ancestors(&[7], &[9, 11], &[3, 6, 9, 11]);
634 }
633 }
635
634
636 /// An interesting case found by a random generator similar to
635 /// An interesting case found by a random generator similar to
637 /// the one in test-ancestor.py. An early version of Rust MissingAncestors
636 /// the one in test-ancestor.py. An early version of Rust MissingAncestors
638 /// failed this, yet none of the integration tests of the whole suite
637 /// failed this, yet none of the integration tests of the whole suite
639 /// catched it.
638 /// catched it.
640 #[test]
639 #[test]
641 fn test_remove_ancestors_from_case1() {
640 fn test_remove_ancestors_from_case1() {
642 let graph: VecGraph = vec![
641 let graph: VecGraph = vec![
643 [NULL_REVISION, NULL_REVISION],
642 [NULL_REVISION, NULL_REVISION],
644 [0, NULL_REVISION],
643 [0, NULL_REVISION],
645 [1, 0],
644 [1, 0],
646 [2, 1],
645 [2, 1],
647 [3, NULL_REVISION],
646 [3, NULL_REVISION],
648 [4, NULL_REVISION],
647 [4, NULL_REVISION],
649 [5, 1],
648 [5, 1],
650 [2, NULL_REVISION],
649 [2, NULL_REVISION],
651 [7, NULL_REVISION],
650 [7, NULL_REVISION],
652 [8, NULL_REVISION],
651 [8, NULL_REVISION],
653 [9, NULL_REVISION],
652 [9, NULL_REVISION],
654 [10, 1],
653 [10, 1],
655 [3, NULL_REVISION],
654 [3, NULL_REVISION],
656 [12, NULL_REVISION],
655 [12, NULL_REVISION],
657 [13, NULL_REVISION],
656 [13, NULL_REVISION],
658 [14, NULL_REVISION],
657 [14, NULL_REVISION],
659 [4, NULL_REVISION],
658 [4, NULL_REVISION],
660 [16, NULL_REVISION],
659 [16, NULL_REVISION],
661 [17, NULL_REVISION],
660 [17, NULL_REVISION],
662 [18, NULL_REVISION],
661 [18, NULL_REVISION],
663 [19, 11],
662 [19, 11],
664 [20, NULL_REVISION],
663 [20, NULL_REVISION],
665 [21, NULL_REVISION],
664 [21, NULL_REVISION],
666 [22, NULL_REVISION],
665 [22, NULL_REVISION],
667 [23, NULL_REVISION],
666 [23, NULL_REVISION],
668 [2, NULL_REVISION],
667 [2, NULL_REVISION],
669 [3, NULL_REVISION],
668 [3, NULL_REVISION],
670 [26, 24],
669 [26, 24],
671 [27, NULL_REVISION],
670 [27, NULL_REVISION],
672 [28, NULL_REVISION],
671 [28, NULL_REVISION],
673 [12, NULL_REVISION],
672 [12, NULL_REVISION],
674 [1, NULL_REVISION],
673 [1, NULL_REVISION],
675 [1, 9],
674 [1, 9],
676 [32, NULL_REVISION],
675 [32, NULL_REVISION],
677 [33, NULL_REVISION],
676 [33, NULL_REVISION],
678 [34, 31],
677 [34, 31],
679 [35, NULL_REVISION],
678 [35, NULL_REVISION],
680 [36, 26],
679 [36, 26],
681 [37, NULL_REVISION],
680 [37, NULL_REVISION],
682 [38, NULL_REVISION],
681 [38, NULL_REVISION],
683 [39, NULL_REVISION],
682 [39, NULL_REVISION],
684 [40, NULL_REVISION],
683 [40, NULL_REVISION],
685 [41, NULL_REVISION],
684 [41, NULL_REVISION],
686 [42, 26],
685 [42, 26],
687 [0, NULL_REVISION],
686 [0, NULL_REVISION],
688 [44, NULL_REVISION],
687 [44, NULL_REVISION],
689 [45, 4],
688 [45, 4],
690 [40, NULL_REVISION],
689 [40, NULL_REVISION],
691 [47, NULL_REVISION],
690 [47, NULL_REVISION],
692 [36, 0],
691 [36, 0],
693 [49, NULL_REVISION],
692 [49, NULL_REVISION],
694 [NULL_REVISION, NULL_REVISION],
693 [NULL_REVISION, NULL_REVISION],
695 [51, NULL_REVISION],
694 [51, NULL_REVISION],
696 [52, NULL_REVISION],
695 [52, NULL_REVISION],
697 [53, NULL_REVISION],
696 [53, NULL_REVISION],
698 [14, NULL_REVISION],
697 [14, NULL_REVISION],
699 [55, NULL_REVISION],
698 [55, NULL_REVISION],
700 [15, NULL_REVISION],
699 [15, NULL_REVISION],
701 [23, NULL_REVISION],
700 [23, NULL_REVISION],
702 [58, NULL_REVISION],
701 [58, NULL_REVISION],
703 [59, NULL_REVISION],
702 [59, NULL_REVISION],
704 [2, NULL_REVISION],
703 [2, NULL_REVISION],
705 [61, 59],
704 [61, 59],
706 [62, NULL_REVISION],
705 [62, NULL_REVISION],
707 [63, NULL_REVISION],
706 [63, NULL_REVISION],
708 [NULL_REVISION, NULL_REVISION],
707 [NULL_REVISION, NULL_REVISION],
709 [65, NULL_REVISION],
708 [65, NULL_REVISION],
710 [66, NULL_REVISION],
709 [66, NULL_REVISION],
711 [67, NULL_REVISION],
710 [67, NULL_REVISION],
712 [68, NULL_REVISION],
711 [68, NULL_REVISION],
713 [37, 28],
712 [37, 28],
714 [69, 25],
713 [69, 25],
715 [71, NULL_REVISION],
714 [71, NULL_REVISION],
716 [72, NULL_REVISION],
715 [72, NULL_REVISION],
717 [50, 2],
716 [50, 2],
718 [74, NULL_REVISION],
717 [74, NULL_REVISION],
719 [12, NULL_REVISION],
718 [12, NULL_REVISION],
720 [18, NULL_REVISION],
719 [18, NULL_REVISION],
721 [77, NULL_REVISION],
720 [77, NULL_REVISION],
722 [78, NULL_REVISION],
721 [78, NULL_REVISION],
723 [79, NULL_REVISION],
722 [79, NULL_REVISION],
724 [43, 33],
723 [43, 33],
725 [81, NULL_REVISION],
724 [81, NULL_REVISION],
726 [82, NULL_REVISION],
725 [82, NULL_REVISION],
727 [83, NULL_REVISION],
726 [83, NULL_REVISION],
728 [84, 45],
727 [84, 45],
729 [85, NULL_REVISION],
728 [85, NULL_REVISION],
730 [86, NULL_REVISION],
729 [86, NULL_REVISION],
731 [NULL_REVISION, NULL_REVISION],
730 [NULL_REVISION, NULL_REVISION],
732 [88, NULL_REVISION],
731 [88, NULL_REVISION],
733 [NULL_REVISION, NULL_REVISION],
732 [NULL_REVISION, NULL_REVISION],
734 [76, 83],
733 [76, 83],
735 [44, NULL_REVISION],
734 [44, NULL_REVISION],
736 [92, NULL_REVISION],
735 [92, NULL_REVISION],
737 [93, NULL_REVISION],
736 [93, NULL_REVISION],
738 [9, NULL_REVISION],
737 [9, NULL_REVISION],
739 [95, 67],
738 [95, 67],
740 [96, NULL_REVISION],
739 [96, NULL_REVISION],
741 [97, NULL_REVISION],
740 [97, NULL_REVISION],
742 [NULL_REVISION, NULL_REVISION],
741 [NULL_REVISION, NULL_REVISION],
743 ];
742 ];
744 let problem_rev = 28 as Revision;
743 let problem_rev = 28 as Revision;
745 let problem_base = 70 as Revision;
744 let problem_base = 70 as Revision;
746 // making the problem obvious: problem_rev is a parent of problem_base
745 // making the problem obvious: problem_rev is a parent of problem_base
747 assert_eq!(graph.parents(problem_base).unwrap()[1], problem_rev);
746 assert_eq!(graph.parents(problem_base).unwrap()[1], problem_rev);
748
747
749 let mut missing_ancestors: MissingAncestors<VecGraph> =
748 let mut missing_ancestors: MissingAncestors<VecGraph> =
750 MissingAncestors::new(
749 MissingAncestors::new(
751 graph,
750 graph,
752 [60, 26, 70, 3, 96, 19, 98, 49, 97, 47, 1, 6]
751 [60, 26, 70, 3, 96, 19, 98, 49, 97, 47, 1, 6]
753 .iter()
752 .iter()
754 .cloned(),
753 .cloned(),
755 );
754 );
756 assert!(missing_ancestors.bases.contains(&problem_base));
755 assert!(missing_ancestors.bases.contains(&problem_base));
757
756
758 let mut revs: HashSet<Revision> =
757 let mut revs: HashSet<Revision> =
759 [4, 12, 41, 28, 68, 38, 1, 30, 56, 44]
758 [4, 12, 41, 28, 68, 38, 1, 30, 56, 44]
760 .iter()
759 .iter()
761 .cloned()
760 .cloned()
762 .collect();
761 .collect();
763 missing_ancestors.remove_ancestors_from(&mut revs).unwrap();
762 missing_ancestors.remove_ancestors_from(&mut revs).unwrap();
764 assert!(!revs.contains(&problem_rev));
763 assert!(!revs.contains(&problem_rev));
765 }
764 }
766
765
767 }
766 }
General Comments 0
You need to be logged in to leave comments. Login now