Skip to content

Commit 408fa92

Browse files
author
Markus Westerlind
committed
fix: Don't create overlapping prefix_eq/suffix_eq in the LCS
Regressed in #89
1 parent 1216ff5 commit 408fa92

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

diffus-derive-test/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,33 @@ mod test {
9191
}
9292
}
9393

94+
#[test]
95+
fn changed_contents() {
96+
let left = vec![Identified { id: 1, value: 0 }];
97+
let right = vec![Identified { id: 1, value: 1 }];
98+
99+
let diff = left.diff(&right);
100+
101+
use edit::{self, collection};
102+
103+
if let edit::Edit::Change(diff) = diff {
104+
let diff = diff.into_iter().collect::<Vec<_>>();
105+
106+
assert_eq!(diff.len(), 1);
107+
108+
if let &collection::Edit::Change(EditedIdentified {
109+
id: edit::Edit::Copy(&1),
110+
value: edit::Edit::Change((&0, &1)),
111+
}) = &diff[0]
112+
{
113+
} else {
114+
unreachable!()
115+
}
116+
} else {
117+
unreachable!()
118+
}
119+
}
120+
94121
#[derive(Diffus)]
95122
enum NestedTest {
96123
T { test: Test },

diffus/src/lcs.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,32 @@ where
2828
I: DoubleEndedIterator<Item = T>,
2929
J: DoubleEndedIterator<Item = T>,
3030
{
31-
let prefix_eq = x().zip(y()).take_while(|(x, y)| x.same(y)).count();
32-
let suffix_eq = x()
33-
.rev()
34-
.zip(y().rev())
35-
.take_while(|(x, y)| x.same(y))
36-
.count();
31+
let mut prefix_eq = 0;
32+
let mut suffix_eq = 0;
33+
{
34+
let mut x_iter = x();
35+
let mut y_iter = y();
36+
// We must not compute an overlapping `prefix_eq` and `suffix_eq` so we only check the suffix
37+
// if there is something that is not the same in the middle of the iterators
38+
let mut check_suffix = false;
39+
loop {
40+
match (x_iter.next(), y_iter.next()) {
41+
(Some(x), Some(y)) if x.same(&y) => prefix_eq += 1,
42+
(Some(_), Some(_)) => {
43+
check_suffix = true;
44+
break;
45+
}
46+
(None, _) | (_, None) => break,
47+
}
48+
}
49+
if check_suffix {
50+
suffix_eq = x_iter
51+
.rev()
52+
.zip(y_iter.rev())
53+
.take_while(|(x, y)| x.same(y))
54+
.count();
55+
}
56+
}
3757

3858
let width = x_len.saturating_sub(prefix_eq + suffix_eq) + 1;
3959
let height = y_len.saturating_sub(prefix_eq + suffix_eq) + 1;

0 commit comments

Comments
 (0)