comparison rust/hg-core/src/dagops.rs @ 51259:ed6683d4cb29

rust-index: implement faster retain heads using a vec instead of a hashset This is the same optimization that the C index does, we're only catching up now because this showed up as slow in benchmarking.
author Raphaël Gomès <rgomes@octobus.net>
date Wed, 29 Nov 2023 10:04:41 -0500
parents 532e74ad3ff6
children c4f1a790bda8
comparison
equal deleted inserted replaced
51258:8b89f7cc953a 51259:ed6683d4cb29
11 //! - By *relative heads* of a collection of revision numbers (`Revision`), we 11 //! - By *relative heads* of a collection of revision numbers (`Revision`), we
12 //! mean those revisions that have no children among the collection. 12 //! mean those revisions that have no children among the collection.
13 //! - Similarly *relative roots* of a collection of `Revision`, we mean those 13 //! - Similarly *relative roots* of a collection of `Revision`, we mean those
14 //! whose parents, if any, don't belong to the collection. 14 //! whose parents, if any, don't belong to the collection.
15 use super::{Graph, GraphError, Revision, NULL_REVISION}; 15 use super::{Graph, GraphError, Revision, NULL_REVISION};
16 use crate::ancestors::AncestorsIterator; 16 use crate::{ancestors::AncestorsIterator, BaseRevision};
17 use std::collections::{BTreeSet, HashSet}; 17 use std::collections::{BTreeSet, HashSet};
18 18
19 fn remove_parents<S: std::hash::BuildHasher>( 19 fn remove_parents<S: std::hash::BuildHasher>(
20 graph: &impl Graph, 20 graph: &impl Graph,
21 rev: Revision, 21 rev: Revision,
74 // mutating 74 // mutating
75 let as_vec: Vec<Revision> = revs.iter().cloned().collect(); 75 let as_vec: Vec<Revision> = revs.iter().cloned().collect();
76 for rev in as_vec { 76 for rev in as_vec {
77 if rev != NULL_REVISION { 77 if rev != NULL_REVISION {
78 remove_parents(graph, rev, revs)?; 78 remove_parents(graph, rev, revs)?;
79 }
80 }
81 Ok(())
82 }
83
84 /// Optimized version of `retain_heads` that expects an zeroed array of the size
85 /// of the graph, to act as a faster but less space-efficient `HashSet`.
86 ///
87 /// # Panics
88 ///
89 /// Can panic if `not_heads` is shorten than the length of graph.
90 pub fn retain_heads_fast(
91 graph: &impl Graph,
92 not_heads: &mut [bool],
93 filtered_revs: &HashSet<Revision>,
94 ) -> Result<(), GraphError> {
95 for idx in (0..not_heads.len()).rev() {
96 let rev = Revision(idx as BaseRevision);
97 if !not_heads[idx] && filtered_revs.contains(&rev) {
98 not_heads[idx] = true;
99 continue;
100 }
101 for parent in graph.parents(rev)?.iter() {
102 if *parent != NULL_REVISION {
103 not_heads[parent.0 as usize] = true;
104 }
79 } 105 }
80 } 106 }
81 Ok(()) 107 Ok(())
82 } 108 }
83 109