revset: move ReverseRevsetGraphIterator into revset module

The iterator is not specific to the implementation in
`revset_graph_iterator`, so it belongs in the standard `revset`
module.
This commit is contained in:
Martin von Zweigbergk 2023-03-13 22:14:06 -07:00 committed by Martin von Zweigbergk
parent f62fac24ac
commit 3871efd2f9
5 changed files with 112 additions and 112 deletions

View file

@ -1488,6 +1488,49 @@ pub struct RevsetWorkspaceContext<'a> {
pub workspace_root: &'a Path,
}
pub struct ReverseRevsetGraphIterator<'index> {
items: Vec<(IndexEntry<'index>, Vec<RevsetGraphEdge>)>,
}
impl<'index> ReverseRevsetGraphIterator<'index> {
pub fn new<'revset>(
input: Box<dyn Iterator<Item = (IndexEntry<'index>, Vec<RevsetGraphEdge>)> + 'revset>,
) -> Self {
let mut entries = vec![];
let mut reverse_edges: HashMap<IndexPosition, Vec<RevsetGraphEdge>> = HashMap::new();
for (entry, edges) in input {
for RevsetGraphEdge { target, edge_type } in edges {
reverse_edges
.entry(target)
.or_default()
.push(RevsetGraphEdge {
target: entry.position(),
edge_type,
})
}
entries.push(entry);
}
let mut items = vec![];
for entry in entries.into_iter() {
let edges = reverse_edges
.get(&entry.position())
.cloned()
.unwrap_or_default();
items.push((entry, edges));
}
Self { items }
}
}
impl<'index> Iterator for ReverseRevsetGraphIterator<'index> {
type Item = (IndexEntry<'index>, Vec<RevsetGraphEdge>);
fn next(&mut self) -> Option<Self::Item> {
self.items.pop()
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -13,7 +13,7 @@
// limitations under the License.
use std::cmp::min;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::{BTreeMap, HashSet};
use crate::default_index_store::{IndexEntry, IndexPosition};
use crate::nightly_shims::BTreeMapExt;
@ -270,46 +270,3 @@ impl<'revset, 'index> Iterator for RevsetGraphIterator<'revset, 'index> {
Some((index_entry, edges))
}
}
pub struct ReverseRevsetGraphIterator<'index> {
items: Vec<(IndexEntry<'index>, Vec<RevsetGraphEdge>)>,
}
impl<'index> ReverseRevsetGraphIterator<'index> {
pub fn new<'revset>(
input: Box<dyn Iterator<Item = (IndexEntry<'index>, Vec<RevsetGraphEdge>)> + 'revset>,
) -> Self {
let mut entries = vec![];
let mut reverse_edges: HashMap<IndexPosition, Vec<RevsetGraphEdge>> = HashMap::new();
for (entry, edges) in input {
for RevsetGraphEdge { target, edge_type } in edges {
reverse_edges
.entry(target)
.or_default()
.push(RevsetGraphEdge {
target: entry.position(),
edge_type,
})
}
entries.push(entry);
}
let mut items = vec![];
for entry in entries.into_iter() {
let edges = reverse_edges
.get(&entry.position())
.cloned()
.unwrap_or_default();
items.push((entry, edges));
}
Self { items }
}
}
impl<'index> Iterator for ReverseRevsetGraphIterator<'index> {
type Item = (IndexEntry<'index>, Vec<RevsetGraphEdge>);
fn next(&mut self) -> Option<Self::Item> {
self.items.pop()
}
}

View file

@ -15,15 +15,16 @@
use std::path::Path;
use assert_matches::assert_matches;
use itertools::Itertools;
use jujutsu_lib::backend::{CommitId, MillisSinceEpoch, ObjectId, Signature, Timestamp};
use jujutsu_lib::default_revset_engine::resolve_symbol;
use jujutsu_lib::default_revset_engine::{resolve_symbol, revset_for_commits};
use jujutsu_lib::git;
use jujutsu_lib::op_store::{RefTarget, WorkspaceId};
use jujutsu_lib::repo::Repo;
use jujutsu_lib::repo_path::RepoPath;
use jujutsu_lib::revset::{
optimize, parse, RevsetAliasesMap, RevsetError, RevsetExpression, RevsetFilterPredicate,
RevsetIteratorExt, RevsetWorkspaceContext,
optimize, parse, ReverseRevsetGraphIterator, RevsetAliasesMap, RevsetError, RevsetExpression,
RevsetFilterPredicate, RevsetGraphEdge, RevsetIteratorExt, RevsetWorkspaceContext,
};
use jujutsu_lib::settings::GitSettings;
use jujutsu_lib::workspace::Workspace;
@ -2011,3 +2012,64 @@ fn test_evaluate_expression_file(use_git: bool) {
vec![commit4.id().clone()]
);
}
#[test]
fn test_reverse_graph_iterator() {
let settings = testutils::user_settings();
let test_repo = TestRepo::init(true);
let repo = &test_repo.repo;
// Tests that merges, forks, direct edges, indirect edges, and "missing" edges
// are correct in reversed graph. "Missing" edges (i.e. edges to commits not
// in the input set) won't be part of the reversed graph. Conversely, there
// won't be missing edges to children not in the input.
//
// F
// |\
// D E
// |/
// C
// |
// b
// |
// A
// |
// root
let mut tx = repo.start_transaction(&settings, "test");
let mut graph_builder = CommitGraphBuilder::new(&settings, tx.mut_repo());
let commit_a = graph_builder.initial_commit();
let commit_b = graph_builder.commit_with_parents(&[&commit_a]);
let commit_c = graph_builder.commit_with_parents(&[&commit_b]);
let commit_d = graph_builder.commit_with_parents(&[&commit_c]);
let commit_e = graph_builder.commit_with_parents(&[&commit_c]);
let commit_f = graph_builder.commit_with_parents(&[&commit_d, &commit_e]);
let repo = tx.commit();
let pos_c = repo.index().commit_id_to_pos(commit_c.id()).unwrap();
let pos_d = repo.index().commit_id_to_pos(commit_d.id()).unwrap();
let pos_e = repo.index().commit_id_to_pos(commit_e.id()).unwrap();
let pos_f = repo.index().commit_id_to_pos(commit_f.id()).unwrap();
let revset = revset_for_commits(
&repo,
&[&commit_a, &commit_c, &commit_d, &commit_e, &commit_f],
);
let commits = ReverseRevsetGraphIterator::new(revset.iter_graph()).collect_vec();
assert_eq!(commits.len(), 5);
assert_eq!(commits[0].0.commit_id(), *commit_a.id());
assert_eq!(commits[1].0.commit_id(), *commit_c.id());
assert_eq!(commits[2].0.commit_id(), *commit_d.id());
assert_eq!(commits[3].0.commit_id(), *commit_e.id());
assert_eq!(commits[4].0.commit_id(), *commit_f.id());
assert_eq!(commits[0].1, vec![RevsetGraphEdge::indirect(pos_c)]);
assert_eq!(
commits[1].1,
vec![
RevsetGraphEdge::direct(pos_e),
RevsetGraphEdge::direct(pos_d),
]
);
assert_eq!(commits[2].1, vec![RevsetGraphEdge::direct(pos_f)]);
assert_eq!(commits[3].1, vec![RevsetGraphEdge::direct(pos_f)]);
assert_eq!(commits[4].1, vec![]);
}

View file

@ -16,7 +16,7 @@ use itertools::Itertools;
use jujutsu_lib::default_revset_engine::revset_for_commits;
use jujutsu_lib::repo::Repo;
use jujutsu_lib::revset::RevsetGraphEdge;
use jujutsu_lib::revset_graph_iterator::{ReverseRevsetGraphIterator, RevsetGraphIterator};
use jujutsu_lib::revset_graph_iterator::RevsetGraphIterator;
use test_case::test_case;
use testutils::{CommitGraphBuilder, TestRepo};
@ -367,64 +367,3 @@ fn test_graph_iterator_edge_escapes_from_(skip_transitive_edges: bool) {
assert_eq!(commits[3].1, vec![RevsetGraphEdge::indirect(pos_a)]);
assert_eq!(commits[4].1, vec![RevsetGraphEdge::missing(pos_root)]);
}
#[test]
fn test_reverse_graph_iterator() {
let settings = testutils::user_settings();
let test_repo = TestRepo::init(true);
let repo = &test_repo.repo;
// Tests that merges, forks, direct edges, indirect edges, and "missing" edges
// are correct in reversed graph. "Missing" edges (i.e. edges to commits not
// in the input set) won't be part of the reversed graph. Conversely, there
// won't be missing edges to children not in the input.
//
// F
// |\
// D E
// |/
// C
// |
// b
// |
// A
// |
// root
let mut tx = repo.start_transaction(&settings, "test");
let mut graph_builder = CommitGraphBuilder::new(&settings, tx.mut_repo());
let commit_a = graph_builder.initial_commit();
let commit_b = graph_builder.commit_with_parents(&[&commit_a]);
let commit_c = graph_builder.commit_with_parents(&[&commit_b]);
let commit_d = graph_builder.commit_with_parents(&[&commit_c]);
let commit_e = graph_builder.commit_with_parents(&[&commit_c]);
let commit_f = graph_builder.commit_with_parents(&[&commit_d, &commit_e]);
let repo = tx.commit();
let pos_c = repo.index().commit_id_to_pos(commit_c.id()).unwrap();
let pos_d = repo.index().commit_id_to_pos(commit_d.id()).unwrap();
let pos_e = repo.index().commit_id_to_pos(commit_e.id()).unwrap();
let pos_f = repo.index().commit_id_to_pos(commit_f.id()).unwrap();
let revset = revset_for_commits(
&repo,
&[&commit_a, &commit_c, &commit_d, &commit_e, &commit_f],
);
let commits = ReverseRevsetGraphIterator::new(revset.iter_graph()).collect_vec();
assert_eq!(commits.len(), 5);
assert_eq!(commits[0].0.commit_id(), *commit_a.id());
assert_eq!(commits[1].0.commit_id(), *commit_c.id());
assert_eq!(commits[2].0.commit_id(), *commit_d.id());
assert_eq!(commits[3].0.commit_id(), *commit_e.id());
assert_eq!(commits[4].0.commit_id(), *commit_f.id());
assert_eq!(commits[0].1, vec![RevsetGraphEdge::indirect(pos_c)]);
assert_eq!(
commits[1].1,
vec![
RevsetGraphEdge::direct(pos_e),
RevsetGraphEdge::direct(pos_d),
]
);
assert_eq!(commits[2].1, vec![RevsetGraphEdge::direct(pos_f)]);
assert_eq!(commits[3].1, vec![RevsetGraphEdge::direct(pos_f)]);
assert_eq!(commits[4].1, vec![]);
}

View file

@ -36,10 +36,9 @@ use jujutsu_lib::op_store::{RefTarget, WorkspaceId};
use jujutsu_lib::repo::{ReadonlyRepo, Repo};
use jujutsu_lib::repo_path::RepoPath;
use jujutsu_lib::revset::{
RevsetAliasesMap, RevsetExpression, RevsetFilterPredicate, RevsetGraphEdge,
RevsetGraphEdgeType, RevsetIteratorExt,
ReverseRevsetGraphIterator, RevsetAliasesMap, RevsetExpression, RevsetFilterPredicate,
RevsetGraphEdge, RevsetGraphEdgeType, RevsetIteratorExt,
};
use jujutsu_lib::revset_graph_iterator::ReverseRevsetGraphIterator;
use jujutsu_lib::rewrite::{back_out_commit, merge_commit_trees, rebase_commit, DescendantRebaser};
use jujutsu_lib::settings::UserSettings;
use jujutsu_lib::tree::{merge_trees, Tree};