refactor: can use multiple ids inpu in find path

This commit is contained in:
Zixuan Chen 2022-10-18 18:03:59 +08:00
parent 15c60aece0
commit 780cf84610
2 changed files with 36 additions and 23 deletions

View file

@ -82,7 +82,7 @@ pub(crate) trait Dag {
trait DagUtils: Dag {
fn find_common_ancestor(&self, a_id: ID, b_id: ID) -> SmallVec<[ID; 2]>;
fn get_vv(&self, id: ID) -> VersionVector;
fn find_path(&self, from: ID, to: ID) -> VersionVectorDiff;
fn find_path(&self, from: &[ID], to: &[ID]) -> VersionVectorDiff;
fn iter(&self) -> DagIterator<'_, Self::Node>
where
Self: Sized;
@ -108,7 +108,7 @@ impl<T: Dag> DagUtils for T {
///
#[inline]
fn find_common_ancestor(&self, a_id: ID, b_id: ID) -> SmallVec<[ID; 2]> {
find_common_ancestor(&|id| self.get(id), a_id, b_id)
find_common_ancestor(&|id| self.get(id), &[a_id], &[b_id])
}
/// TODO: we probably need cache to speedup this
@ -118,7 +118,7 @@ impl<T: Dag> DagUtils for T {
}
#[inline(always)]
fn find_path(&self, from: ID, to: ID) -> VersionVectorDiff {
fn find_path(&self, from: &[ID], to: &[ID]) -> VersionVectorDiff {
let mut ans = VersionVectorDiff::default();
_find_common_ancestor(
&|v| self.get(v),
@ -285,7 +285,7 @@ impl<'a> OrdIdSpan<'a> {
}
#[inline(always)]
fn find_common_ancestor<'a, F, D>(get: &'a F, a_id: ID, b_id: ID) -> SmallVec<[ID; 2]>
fn find_common_ancestor<'a, F, D>(get: &'a F, a_id: &[ID], b_id: &[ID]) -> SmallVec<[ID; 2]>
where
D: DagNode + 'a,
F: Fn(ID) -> Option<&'a D>,
@ -299,8 +299,8 @@ where
/// - deep whether keep searching until the min of non-shared node is found
fn _find_common_ancestor<'a, F, D, G>(
get: &'a F,
a_id: ID,
b_id: ID,
a_ids: &[ID],
b_ids: &[ID],
notify: &mut G,
deep: bool,
) -> FxHashMap<ClientID, Counter>
@ -311,8 +311,12 @@ where
{
let mut ans: FxHashMap<ClientID, Counter> = Default::default();
let mut queue: BinaryHeap<(OrdIdSpan, NodeType)> = BinaryHeap::new();
queue.push((OrdIdSpan::from_dag_node(a_id, get).unwrap(), NodeType::A));
queue.push((OrdIdSpan::from_dag_node(b_id, get).unwrap(), NodeType::B));
for id in a_ids {
queue.push((OrdIdSpan::from_dag_node(*id, get).unwrap(), NodeType::A));
}
for id in b_ids {
queue.push((OrdIdSpan::from_dag_node(*id, get).unwrap(), NodeType::B));
}
let mut visited: HashMap<ClientID, (Counter, NodeType), _> = FxHashMap::default();
// invariants in this method:
//
@ -323,8 +327,8 @@ where
// - we may visit nodes that are before the common ancestors
// type count in the queue. if both are zero, we can stop
let mut a_count = 1;
let mut b_count = 1;
let mut a_count = a_ids.len();
let mut b_count = b_ids.len();
let mut min = None;
while let Some((node, mut node_type)) = queue.pop() {
match node_type {

View file

@ -441,7 +441,7 @@ mod find_path {
a.push(1);
b.push(1);
a.merge(&b);
let actual = a.find_path(ID::new(0, 0), ID::new(1, 0));
let actual = a.find_path(&[ID::new(0, 0)], &[ID::new(1, 0)]);
assert_eq!(
actual,
VersionVectorDiff {
@ -463,7 +463,7 @@ mod find_path {
// 0 - 1
a.push(1);
a.merge(&b);
let actual = a.find_path(ID::new(0, 1), ID::new(1, 0));
let actual = a.find_path(&[ID::new(0, 1)], &[ID::new(1, 0)]);
assert_eq!(
actual,
VersionVectorDiff {
@ -480,23 +480,23 @@ mod find_path {
a.push(2);
b.push(1);
b.merge(&a);
b.push(1);
b.push(2);
a.push(2);
b.merge(&a);
// println!("{}", b.mermaid());
let actual = b.find_path(ID::new(0, 3), ID::new(1, 1));
let actual = b.find_path(&[ID::new(0, 3)], &[ID::new(1, 2)]);
assert_eq!(
actual,
VersionVectorDiff {
to_left: fx_map!(0 => CounterSpan { from: 2, to: 4 }),
to_right: fx_map!(1 => CounterSpan { from: 0, to: 2 })
to_right: fx_map!(1 => CounterSpan { from: 0, to: 3 })
}
);
let actual = b.find_path(ID::new(1, 1), ID::new(0, 3));
let actual = b.find_path(&[ID::new(1, 1), ID::new(1, 2)], &[ID::new(0, 3)]);
assert_eq!(
actual,
VersionVectorDiff {
to_left: fx_map!(1 => CounterSpan { from: 0, to: 2 }),
to_left: fx_map!(1 => CounterSpan { from: 0, to: 3 }),
to_right: fx_map!(0 => CounterSpan { from: 2, to: 4 })
}
);
@ -528,17 +528,18 @@ mod find_path {
}
// println!("{}", a.mermaid());
for (i, (node, vv)) in nodes.iter().enumerate() {
let mut vec: Vec<_> = nodes.iter().enumerate().collect();
for &(i, (node, vv)) in vec.iter() {
if i > 3 {
break;
}
for (j, (other_node, other_vv)) in nodes.iter().enumerate() {
if i == j {
for &(j, (other_node, other_vv)) in vec.iter() {
if i >= j {
continue;
}
let actual = a.find_path(node.id, other_node.id);
let actual = a.find_path(&[node.id], &[other_node.id]);
let expected = vv.clone() - other_vv.clone();
prop_assert_eq!(
actual,
@ -549,6 +550,14 @@ mod find_path {
node.id,
other_node.id
);
for k in j + 1..nodes.len() {
let mut vv = vv.clone();
vv.merge(other_vv);
let actual = a.find_path(&[node.id, other_node.id], &[vec[k].1 .0.id]);
let expected = vv.clone() - vec[k].1 .1.clone();
prop_assert_eq!(actual, expected);
}
}
}
@ -609,14 +618,14 @@ mod find_path {
proptest! {
#[test]
fn proptest_path(
interactions in prop::collection::vec(gen_interaction(5), 0..50 * PROPTEST_FACTOR_10),
interactions in prop::collection::vec(gen_interaction(5), 0..10 * PROPTEST_FACTOR_10),
) {
test_find_path(5, interactions)?;
}
#[test]
fn proptest_path_large(
interactions in prop::collection::vec(gen_interaction(10), 0..10 * PROPTEST_FACTOR_10 * PROPTEST_FACTOR_10 + 10),
interactions in prop::collection::vec(gen_interaction(10), 0..5 * PROPTEST_FACTOR_10 * PROPTEST_FACTOR_10 + 10),
) {
test_find_path(10, interactions)?;
}