##// END OF EJS Templates
rust: itering less on MissingAncestors.bases for max()...
Georges Racinet -
r41866:9060af28 default
parent child Browse files
Show More
@@ -38,6 +38,7 b' pub struct LazyAncestors<G: Graph + Clon'
38 38 pub struct MissingAncestors<G: Graph> {
39 39 graph: G,
40 40 bases: HashSet<Revision>,
41 max_base: Revision,
41 42 }
42 43
43 44 impl<G: Graph> AncestorsIterator<G> {
@@ -209,7 +210,13 b' impl<G: Graph + Clone> LazyAncestors<G> '
209 210
210 211 impl<G: Graph> MissingAncestors<G> {
211 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 222 pub fn has_bases(&self) -> bool {
@@ -232,17 +239,33 b' impl<G: Graph> MissingAncestors<G> {'
232 239 }
233 240
234 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 245 dagops::retain_heads(&self.graph, &mut self.bases)?;
237 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 252 pub fn add_bases(
241 253 &mut self,
242 254 new_bases: impl IntoIterator<Item = Revision>,
243 255 ) {
244 self.bases
245 .extend(new_bases.into_iter().filter(|&rev| rev != NULL_REVISION));
256 let mut max_base = self.max_base;
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 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 285 // anything in revs > start is definitely not an ancestor of bases
263 286 // revs <= start need to be investigated
264 // TODO optim: if a missingancestors is to be used several times,
265 // we shouldn't need to iterate each time on bases
266 let start = match self.bases.iter().cloned().max() {
267 Some(m) => m,
268 None => { // self.bases is empty
269 return Ok(());
270 }
271 };
287 if self.max_base == NULL_REVISION {
288 return Ok(());
289 }
290
272 291 // whatever happens, we'll keep at least keepcount of them
273 292 // knowing this gives us a earlier stop condition than
274 293 // going all the way to the root
275 let keepcount = revs.iter().filter(|r| **r > start).count();
294 let keepcount = revs.iter().filter(|r| **r > self.max_base).count();
276 295
277 let mut curr = start;
296 let mut curr = self.max_base;
278 297 while curr != NULL_REVISION && revs.len() > keepcount {
279 298 if self.bases.contains(&curr) {
280 299 revs.remove(&curr);
@@ -285,12 +304,17 b' impl<G: Graph> MissingAncestors<G> {'
285 304 Ok(())
286 305 }
287 306
288 /// Add rev's parents to self.bases
307 /// Add the parents of `rev` to `self.bases`
308 ///
309 /// This has no effect on `self.max_base`
289 310 #[inline]
290 311 fn add_parents(&mut self, rev: Revision) -> Result<(), GraphError> {
291 // No need to bother the set with inserting NULL_REVISION over and
292 // over
312 if rev == NULL_REVISION {
313 return Ok(());
314 }
293 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 318 if p != NULL_REVISION {
295 319 self.bases.insert(p);
296 320 }
@@ -320,12 +344,8 b' impl<G: Graph> MissingAncestors<G> {'
320 344 if revs_visit.is_empty() {
321 345 return Ok(Vec::new());
322 346 }
323
324 let max_bases =
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);
347 let max_revs = revs_visit.iter().cloned().max().unwrap();
348 let start = max(self.max_base, max_revs);
329 349
330 350 // TODO heuristics for with_capacity()?
331 351 let mut missing: Vec<Revision> = Vec::new();
@@ -571,11 +591,13 b' mod tests {'
571 591 missing_ancestors.get_bases().iter().cloned().collect();
572 592 as_vec.sort();
573 593 assert_eq!(as_vec, [1, 3, 5]);
594 assert_eq!(missing_ancestors.max_base, 5);
574 595
575 596 missing_ancestors.add_bases([3, 7, 8].iter().cloned());
576 597 as_vec = missing_ancestors.get_bases().iter().cloned().collect();
577 598 as_vec.sort();
578 599 assert_eq!(as_vec, [1, 3, 5, 7, 8]);
600 assert_eq!(missing_ancestors.max_base, 8);
579 601
580 602 as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect();
581 603 as_vec.sort();
@@ -46,7 +46,9 b" pub fn heads<'a>("
46 46 let mut heads: HashSet<Revision> = iter_revs.clone().cloned().collect();
47 47 heads.remove(&NULL_REVISION);
48 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 53 Ok(heads)
52 54 }
@@ -71,7 +73,9 b' pub fn retain_heads('
71 73 // mutating
72 74 let as_vec: Vec<Revision> = revs.iter().cloned().collect();
73 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 80 Ok(())
77 81 }
@@ -13,6 +13,11 b' pub mod testing; // unconditionally bui'
13 13 /// 4 bytes, and are liberally converted to ints, whence the i32
14 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 21 pub const NULL_REVISION: Revision = -1;
17 22
18 23 /// Same as `mercurial.node.wdirrev`
General Comments 0
You need to be logged in to leave comments. Login now