##// 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 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 > 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 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 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 #[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