From 780cf84610305f9b17dffb6cd11e507c5c522179 Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Tue, 18 Oct 2022 18:03:59 +0800 Subject: [PATCH] refactor: can use multiple ids inpu in find path --- crates/loro-core/src/dag.rs | 24 +++++++++++++--------- crates/loro-core/src/dag/test.rs | 35 ++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/crates/loro-core/src/dag.rs b/crates/loro-core/src/dag.rs index b67077c1..22a538d7 100644 --- a/crates/loro-core/src/dag.rs +++ b/crates/loro-core/src/dag.rs @@ -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 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 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 @@ -311,8 +311,12 @@ where { let mut ans: FxHashMap = 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 = 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 { diff --git a/crates/loro-core/src/dag/test.rs b/crates/loro-core/src/dag/test.rs index 30cc7200..a00842aa 100644 --- a/crates/loro-core/src/dag/test.rs +++ b/crates/loro-core/src/dag/test.rs @@ -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)?; }