Show More
@@ -556,6 +556,57 b' impl Index {' | |||||
556 | self.head_revs_filtered(&HashSet::new(), true) |
|
556 | self.head_revs_filtered(&HashSet::new(), true) | |
557 | } |
|
557 | } | |
558 |
|
558 | |||
|
559 | /// Return the heads removed and added by advancing from `begin` to `end`. | |||
|
560 | /// In revset language, we compute: | |||
|
561 | /// - `heads(:begin)-heads(:end)` | |||
|
562 | /// - `heads(:end)-heads(:begin)` | |||
|
563 | pub fn head_revs_diff( | |||
|
564 | &self, | |||
|
565 | begin: Revision, | |||
|
566 | end: Revision, | |||
|
567 | ) -> Result<(Vec<Revision>, Vec<Revision>), GraphError> { | |||
|
568 | let mut heads_added = vec![]; | |||
|
569 | let mut heads_removed = vec![]; | |||
|
570 | ||||
|
571 | let mut acc = HashSet::new(); | |||
|
572 | let Revision(begin) = begin; | |||
|
573 | let Revision(end) = end; | |||
|
574 | let mut i = end; | |||
|
575 | ||||
|
576 | while i > begin { | |||
|
577 | // acc invariant: | |||
|
578 | // `j` is in the set iff `j <= i` and it has children | |||
|
579 | // among `i+1..end` (inclusive) | |||
|
580 | if !acc.remove(&i) { | |||
|
581 | heads_added.push(Revision(i)); | |||
|
582 | } | |||
|
583 | for Revision(parent) in self.parents(Revision(i))? { | |||
|
584 | acc.insert(parent); | |||
|
585 | } | |||
|
586 | i -= 1; | |||
|
587 | } | |||
|
588 | ||||
|
589 | // At this point `acc` contains old revisions that gained new children. | |||
|
590 | // We need to check if they had any children before. If not, those | |||
|
591 | // revisions are the removed heads. | |||
|
592 | while !acc.is_empty() { | |||
|
593 | // acc invariant: | |||
|
594 | // `j` is in the set iff `j <= i` and it has children | |||
|
595 | // among `begin+1..end`, but not among `i+1..begin` (inclusive) | |||
|
596 | ||||
|
597 | assert!(i >= -1); // yes, `-1` can also be a head if the repo is empty | |||
|
598 | if acc.remove(&i) { | |||
|
599 | heads_removed.push(Revision(i)); | |||
|
600 | } | |||
|
601 | for Revision(parent) in self.parents(Revision(i))? { | |||
|
602 | acc.remove(&parent); | |||
|
603 | } | |||
|
604 | i -= 1; | |||
|
605 | } | |||
|
606 | ||||
|
607 | Ok((heads_removed, heads_added)) | |||
|
608 | } | |||
|
609 | ||||
559 | /// Return the head revisions of this index |
|
610 | /// Return the head revisions of this index | |
560 | pub fn head_revs_filtered( |
|
611 | pub fn head_revs_filtered( | |
561 | &self, |
|
612 | &self, |
@@ -315,6 +315,15 b' py_class!(pub class Index |py| {' | |||||
315 | Ok(rust_res) |
|
315 | Ok(rust_res) | |
316 | } |
|
316 | } | |
317 |
|
317 | |||
|
318 | /// get diff in head revisions | |||
|
319 | def headrevsdiff(&self, *args, **_kw) -> PyResult<PyObject> { | |||
|
320 | let rust_res = self.inner_headrevsdiff( | |||
|
321 | py, | |||
|
322 | &args.get_item(py, 0), | |||
|
323 | &args.get_item(py, 1))?; | |||
|
324 | Ok(rust_res) | |||
|
325 | } | |||
|
326 | ||||
318 | /// get filtered head revisions |
|
327 | /// get filtered head revisions | |
319 | def headrevsfiltered(&self, *args, **_kw) -> PyResult<PyObject> { |
|
328 | def headrevsfiltered(&self, *args, **_kw) -> PyResult<PyObject> { | |
320 | let rust_res = self.inner_headrevsfiltered(py, &args.get_item(py, 0))?; |
|
329 | let rust_res = self.inner_headrevsfiltered(py, &args.get_item(py, 0))?; | |
@@ -827,6 +836,38 b' impl Index {' | |||||
827 | .into_object()) |
|
836 | .into_object()) | |
828 | } |
|
837 | } | |
829 |
|
838 | |||
|
839 | fn check_revision( | |||
|
840 | index: &hg::index::Index, | |||
|
841 | rev: UncheckedRevision, | |||
|
842 | py: Python, | |||
|
843 | ) -> PyResult<Revision> { | |||
|
844 | index | |||
|
845 | .check_revision(rev) | |||
|
846 | .ok_or_else(|| rev_not_in_index(py, rev)) | |||
|
847 | } | |||
|
848 | ||||
|
849 | fn inner_headrevsdiff( | |||
|
850 | &self, | |||
|
851 | py: Python, | |||
|
852 | begin: &PyObject, | |||
|
853 | end: &PyObject, | |||
|
854 | ) -> PyResult<PyObject> { | |||
|
855 | let begin = begin.extract::<BaseRevision>(py)?; | |||
|
856 | let end = end.extract::<BaseRevision>(py)?; | |||
|
857 | let index = &mut *self.index(py).borrow_mut(); | |||
|
858 | let begin = | |||
|
859 | Self::check_revision(index, UncheckedRevision(begin - 1), py)?; | |||
|
860 | let end = Self::check_revision(index, UncheckedRevision(end - 1), py)?; | |||
|
861 | let (removed, added) = index | |||
|
862 | .head_revs_diff(begin, end) | |||
|
863 | .map_err(|e| graph_error(py, e))?; | |||
|
864 | let removed: Vec<_> = | |||
|
865 | removed.into_iter().map(PyRevision::from).collect(); | |||
|
866 | let added: Vec<_> = added.into_iter().map(PyRevision::from).collect(); | |||
|
867 | let res = (removed, added).to_py_object(py).into_object(); | |||
|
868 | Ok(res) | |||
|
869 | } | |||
|
870 | ||||
830 | fn inner_headrevsfiltered( |
|
871 | fn inner_headrevsfiltered( | |
831 | &self, |
|
872 | &self, | |
832 | py: Python, |
|
873 | py: Python, |
General Comments 0
You need to be logged in to leave comments.
Login now