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