Show More
@@ -38,6 +38,7 b' pub struct LazyAncestors<G: Graph + Clon' | |||||
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 | max_base: Revision, | |||
41 | } |
|
42 | } | |
42 |
|
43 | |||
43 | impl<G: Graph> AncestorsIterator<G> { |
|
44 | impl<G: Graph> AncestorsIterator<G> { | |
@@ -209,7 +210,13 b' impl<G: Graph + Clone> LazyAncestors<G> ' | |||||
209 |
|
210 | |||
210 | impl<G: Graph> MissingAncestors<G> { |
|
211 | impl<G: Graph> MissingAncestors<G> { | |
211 | pub fn new(graph: G, bases: impl IntoIterator<Item = Revision>) -> Self { |
|
212 | pub fn new(graph: G, bases: impl IntoIterator<Item = Revision>) -> Self { | |
212 | MissingAncestors { graph: graph, bases: bases.into_iter().collect() } |
|
213 | let mut created = MissingAncestors { | |
|
214 | graph: graph, | |||
|
215 | bases: HashSet::new(), | |||
|
216 | max_base: NULL_REVISION, | |||
|
217 | }; | |||
|
218 | created.add_bases(bases); | |||
|
219 | created | |||
213 | } |
|
220 | } | |
214 |
|
221 | |||
215 | pub fn has_bases(&self) -> bool { |
|
222 | pub fn has_bases(&self) -> bool { | |
@@ -232,17 +239,33 b' impl<G: Graph> MissingAncestors<G> {' | |||||
232 | } |
|
239 | } | |
233 |
|
240 | |||
234 | /// Consumes the object and returns the relative heads of its bases. |
|
241 | /// Consumes the object and returns the relative heads of its bases. | |
235 | pub fn into_bases_heads(mut self) -> Result<HashSet<Revision>, GraphError> { |
|
242 | pub fn into_bases_heads( | |
|
243 | mut self, | |||
|
244 | ) -> Result<HashSet<Revision>, GraphError> { | |||
236 | dagops::retain_heads(&self.graph, &mut self.bases)?; |
|
245 | dagops::retain_heads(&self.graph, &mut self.bases)?; | |
237 | Ok(self.bases) |
|
246 | Ok(self.bases) | |
238 | } |
|
247 | } | |
239 |
|
248 | |||
|
249 | /// Add some revisions to `self.bases` | |||
|
250 | /// | |||
|
251 | /// Takes care of keeping `self.max_base` up to date. | |||
240 | pub fn add_bases( |
|
252 | pub fn add_bases( | |
241 | &mut self, |
|
253 | &mut self, | |
242 | new_bases: impl IntoIterator<Item = Revision>, |
|
254 | new_bases: impl IntoIterator<Item = Revision>, | |
243 | ) { |
|
255 | ) { | |
244 | self.bases |
|
256 | let mut max_base = self.max_base; | |
245 | .extend(new_bases.into_iter().filter(|&rev| rev != NULL_REVISION)); |
|
257 | self.bases.extend( | |
|
258 | new_bases | |||
|
259 | .into_iter() | |||
|
260 | .filter(|&rev| rev != NULL_REVISION) | |||
|
261 | .map(|r| { | |||
|
262 | if r > max_base { | |||
|
263 | max_base = r; | |||
|
264 | } | |||
|
265 | r | |||
|
266 | }), | |||
|
267 | ); | |||
|
268 | self.max_base = max_base; | |||
246 | } |
|
269 | } | |
247 |
|
270 | |||
248 | /// Remove all ancestors of self.bases from the revs set (in place) |
|
271 | /// Remove all ancestors of self.bases from the revs set (in place) | |
@@ -261,20 +284,16 b' impl<G: Graph> MissingAncestors<G> {' | |||||
261 | } |
|
284 | } | |
262 | // anything in revs > start is definitely not an ancestor of bases |
|
285 | // anything in revs > start is definitely not an ancestor of bases | |
263 | // revs <= start need to be investigated |
|
286 | // revs <= start need to be investigated | |
264 | // TODO optim: if a missingancestors is to be used several times, |
|
287 | if self.max_base == NULL_REVISION { | |
265 | // we shouldn't need to iterate each time on bases |
|
288 | return Ok(()); | |
266 | let start = match self.bases.iter().cloned().max() { |
|
289 | } | |
267 | Some(m) => m, |
|
290 | ||
268 | None => { // self.bases is empty |
|
|||
269 | return Ok(()); |
|
|||
270 | } |
|
|||
271 | }; |
|
|||
272 | // whatever happens, we'll keep at least keepcount of them |
|
291 | // whatever happens, we'll keep at least keepcount of them | |
273 | // knowing this gives us a earlier stop condition than |
|
292 | // knowing this gives us a earlier stop condition than | |
274 | // going all the way to the root |
|
293 | // going all the way to the root | |
275 |
let keepcount = revs.iter().filter(|r| **r > s |
|
294 | let keepcount = revs.iter().filter(|r| **r > self.max_base).count(); | |
276 |
|
295 | |||
277 |
let mut curr = s |
|
296 | let mut curr = self.max_base; | |
278 | while curr != NULL_REVISION && revs.len() > keepcount { |
|
297 | while curr != NULL_REVISION && revs.len() > keepcount { | |
279 | if self.bases.contains(&curr) { |
|
298 | if self.bases.contains(&curr) { | |
280 | revs.remove(&curr); |
|
299 | revs.remove(&curr); | |
@@ -285,12 +304,17 b' impl<G: Graph> MissingAncestors<G> {' | |||||
285 | Ok(()) |
|
304 | Ok(()) | |
286 | } |
|
305 | } | |
287 |
|
306 | |||
288 |
/// Add |
|
307 | /// Add the parents of `rev` to `self.bases` | |
|
308 | /// | |||
|
309 | /// This has no effect on `self.max_base` | |||
289 | #[inline] |
|
310 | #[inline] | |
290 | fn add_parents(&mut self, rev: Revision) -> Result<(), GraphError> { |
|
311 | fn add_parents(&mut self, rev: Revision) -> Result<(), GraphError> { | |
291 | // No need to bother the set with inserting NULL_REVISION over and |
|
312 | if rev == NULL_REVISION { | |
292 | // over |
|
313 | return Ok(()); | |
|
314 | } | |||
293 | for p in self.graph.parents(rev)?.iter().cloned() { |
|
315 | for p in self.graph.parents(rev)?.iter().cloned() { | |
|
316 | // No need to bother the set with inserting NULL_REVISION over and | |||
|
317 | // over | |||
294 | if p != NULL_REVISION { |
|
318 | if p != NULL_REVISION { | |
295 | self.bases.insert(p); |
|
319 | self.bases.insert(p); | |
296 | } |
|
320 | } | |
@@ -320,12 +344,8 b' impl<G: Graph> MissingAncestors<G> {' | |||||
320 | if revs_visit.is_empty() { |
|
344 | if revs_visit.is_empty() { | |
321 | return Ok(Vec::new()); |
|
345 | return Ok(Vec::new()); | |
322 | } |
|
346 | } | |
323 |
|
347 | let max_revs = revs_visit.iter().cloned().max().unwrap(); | ||
324 | let max_bases = |
|
348 | let start = max(self.max_base, max_revs); | |
325 | bases_visit.iter().cloned().max().unwrap_or(NULL_REVISION); |
|
|||
326 | let max_revs = |
|
|||
327 | revs_visit.iter().cloned().max().unwrap_or(NULL_REVISION); |
|
|||
328 | let start = max(max_bases, max_revs); |
|
|||
329 |
|
349 | |||
330 | // TODO heuristics for with_capacity()? |
|
350 | // TODO heuristics for with_capacity()? | |
331 | let mut missing: Vec<Revision> = Vec::new(); |
|
351 | let mut missing: Vec<Revision> = Vec::new(); | |
@@ -571,11 +591,13 b' mod tests {' | |||||
571 | missing_ancestors.get_bases().iter().cloned().collect(); |
|
591 | missing_ancestors.get_bases().iter().cloned().collect(); | |
572 | as_vec.sort(); |
|
592 | as_vec.sort(); | |
573 | assert_eq!(as_vec, [1, 3, 5]); |
|
593 | assert_eq!(as_vec, [1, 3, 5]); | |
|
594 | assert_eq!(missing_ancestors.max_base, 5); | |||
574 |
|
595 | |||
575 | missing_ancestors.add_bases([3, 7, 8].iter().cloned()); |
|
596 | missing_ancestors.add_bases([3, 7, 8].iter().cloned()); | |
576 | as_vec = missing_ancestors.get_bases().iter().cloned().collect(); |
|
597 | as_vec = missing_ancestors.get_bases().iter().cloned().collect(); | |
577 | as_vec.sort(); |
|
598 | as_vec.sort(); | |
578 | assert_eq!(as_vec, [1, 3, 5, 7, 8]); |
|
599 | assert_eq!(as_vec, [1, 3, 5, 7, 8]); | |
|
600 | assert_eq!(missing_ancestors.max_base, 8); | |||
579 |
|
601 | |||
580 | as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect(); |
|
602 | as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect(); | |
581 | as_vec.sort(); |
|
603 | as_vec.sort(); |
@@ -46,7 +46,9 b" pub fn heads<'a>(" | |||||
46 | let mut heads: HashSet<Revision> = iter_revs.clone().cloned().collect(); |
|
46 | let mut heads: HashSet<Revision> = iter_revs.clone().cloned().collect(); | |
47 | heads.remove(&NULL_REVISION); |
|
47 | heads.remove(&NULL_REVISION); | |
48 | for rev in iter_revs { |
|
48 | for rev in iter_revs { | |
49 | remove_parents(graph, *rev, &mut heads)?; |
|
49 | if *rev != NULL_REVISION { | |
|
50 | remove_parents(graph, *rev, &mut heads)?; | |||
|
51 | } | |||
50 | } |
|
52 | } | |
51 | Ok(heads) |
|
53 | Ok(heads) | |
52 | } |
|
54 | } | |
@@ -71,7 +73,9 b' pub fn retain_heads(' | |||||
71 | // mutating |
|
73 | // mutating | |
72 | let as_vec: Vec<Revision> = revs.iter().cloned().collect(); |
|
74 | let as_vec: Vec<Revision> = revs.iter().cloned().collect(); | |
73 | for rev in as_vec { |
|
75 | for rev in as_vec { | |
74 | remove_parents(graph, rev, revs)?; |
|
76 | if rev != NULL_REVISION { | |
|
77 | remove_parents(graph, rev, revs)?; | |||
|
78 | } | |||
75 | } |
|
79 | } | |
76 | Ok(()) |
|
80 | Ok(()) | |
77 | } |
|
81 | } |
@@ -13,6 +13,11 b' pub mod testing; // unconditionally bui' | |||||
13 | /// 4 bytes, and are liberally converted to ints, whence the i32 |
|
13 | /// 4 bytes, and are liberally converted to ints, whence the i32 | |
14 | pub type Revision = i32; |
|
14 | pub type Revision = i32; | |
15 |
|
15 | |||
|
16 | ||||
|
17 | /// Marker expressing the absence of a parent | |||
|
18 | /// | |||
|
19 | /// Independently of the actual representation, `NULL_REVISION` is guaranteed | |||
|
20 | /// to be smaller that all existing revisions. | |||
16 | pub const NULL_REVISION: Revision = -1; |
|
21 | pub const NULL_REVISION: Revision = -1; | |
17 |
|
22 | |||
18 | /// Same as `mercurial.node.wdirrev` |
|
23 | /// Same as `mercurial.node.wdirrev` |
General Comments 0
You need to be logged in to leave comments.
Login now