# HG changeset patch # User Raphaël Gomès # Date 1698660865 -3600 # Node ID 9f876765cbe22270351a2744ba59ff2685db3906 # Parent a7bba7df9189cdacb2c3f3069f9906cc8944001f rust-index: add support for `headrevsfiltered` The implementation is merged with that of `headrevs` also to make sure that caches are up to date. diff -r a7bba7df9189 -r 9f876765cbe2 rust/hg-core/src/revlog/index.rs --- a/rust/hg-core/src/revlog/index.rs Tue Sep 19 15:21:43 2023 +0200 +++ b/rust/hg-core/src/revlog/index.rs Mon Oct 30 11:14:25 2023 +0100 @@ -263,6 +263,9 @@ /// Cache of the head revisions in this index, kept in sync. Should /// be accessed via the [`Self::head_revs`] method. head_revs: Vec, + /// Cache of the last filtered revisions in this index, used to make sure + /// we haven't changed filters when returning the cached `head_revs`. + filtered_revs: HashSet, } impl Debug for Index { @@ -363,6 +366,7 @@ uses_generaldelta, is_inline: true, head_revs: vec![], + filtered_revs: HashSet::new(), }) } else { Err(HgError::corrupted("unexpected inline revlog length")) @@ -374,6 +378,7 @@ uses_generaldelta, is_inline: false, head_revs: vec![], + filtered_revs: HashSet::new(), }) } } @@ -520,13 +525,36 @@ /// Return the head revisions of this index pub fn head_revs(&mut self) -> Result, GraphError> { - if !self.head_revs.is_empty() { + self.head_revs_filtered(&HashSet::new()) + } + + /// Return the head revisions of this index + pub fn head_revs_filtered( + &mut self, + filtered_revs: &HashSet, + ) -> Result, GraphError> { + if !self.head_revs.is_empty() && filtered_revs == &self.filtered_revs { return Ok(self.head_revs.to_owned()); } - let mut revs: HashSet = (0..self.len()) - .into_iter() - .map(|i| Revision(i as BaseRevision)) - .collect(); + let mut revs: HashSet = + if filtered_revs.is_empty() { + (0..self.len()) + .into_iter() + .map(|i| Revision(i as BaseRevision)) + .collect() + } else { + (0..self.len()) + .into_iter() + .filter_map(|i| { + let r = Revision(i as BaseRevision); + if filtered_revs.contains(&r) { + None + } else { + Some(r) + } + }) + .collect() + }; dagops::retain_heads(self, &mut revs)?; if self.is_empty() { revs.insert(NULL_REVISION); @@ -535,6 +563,7 @@ revs.into_iter().map(Into::into).collect(); as_vec.sort_unstable(); self.head_revs = as_vec.to_owned(); + self.filtered_revs = filtered_revs.to_owned(); Ok(as_vec) } diff -r a7bba7df9189 -r 9f876765cbe2 rust/hg-cpython/src/revlog.rs --- a/rust/hg-cpython/src/revlog.rs Tue Sep 19 15:21:43 2023 +0200 +++ b/rust/hg-cpython/src/revlog.rs Mon Oct 30 11:14:25 2023 +0100 @@ -7,6 +7,8 @@ use crate::{ cindex, + conversion::rev_pyiter_collect, + exceptions::GraphError, utils::{node_from_py_bytes, node_from_py_object}, PyRevision, }; @@ -259,7 +261,20 @@ /// get filtered head revisions def headrevsfiltered(&self, *args, **kw) -> PyResult { - self.call_cindex(py, "headrevsfiltered", args, kw) + let rust_res = self.inner_headrevsfiltered(py, &args.get_item(py, 0))?; + let c_res = self.call_cindex(py, "headrevsfiltered", args, kw)?; + assert_eq!( + rust_res.len(), + c_res.len(py)?, + "filtered heads differ {:?} {}", + rust_res, + c_res + ); + for (index, rev) in rust_res.iter().enumerate() { + let c_rev: BaseRevision = c_res.get_item(py, index)?.extract(py)?; + assert_eq!(c_rev, rev.0); + } + Ok(c_res) } /// True if the object is a snapshot @@ -797,6 +812,19 @@ .collect(); Ok(PyList::new(py, &as_vec).into_object()) } + + fn inner_headrevsfiltered( + &self, + py: Python, + filtered_revs: &PyObject, + ) -> PyResult> { + let index = &mut *self.index(py).borrow_mut(); + let filtered_revs = rev_pyiter_collect(py, filtered_revs, index)?; + + index + .head_revs_filtered(&filtered_revs) + .map_err(|e| GraphError::pynew(py, e)) + } } fn revlog_error(py: Python) -> PyErr {