Mercurial > hg
changeset 51216:9f876765cbe2
rust-index: add support for `headrevsfiltered`
The implementation is merged with that of `headrevs` also to make sure that
caches are up to date.
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Mon, 30 Oct 2023 11:14:25 +0100 |
parents | a7bba7df9189 |
children | 898674a4dbc7 |
files | rust/hg-core/src/revlog/index.rs rust/hg-cpython/src/revlog.rs |
diffstat | 2 files changed, 63 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- 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<Revision>, + /// 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<Revision>, } 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<Vec<Revision>, 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<Revision>, + ) -> Result<Vec<Revision>, GraphError> { + if !self.head_revs.is_empty() && filtered_revs == &self.filtered_revs { return Ok(self.head_revs.to_owned()); } - let mut revs: HashSet<Revision, RandomState> = (0..self.len()) - .into_iter() - .map(|i| Revision(i as BaseRevision)) - .collect(); + let mut revs: HashSet<Revision, RandomState> = + 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) }
--- 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<PyObject> { - 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<Vec<Revision>> { + 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 {