ok/jj
1
0
Fork 0
forked from mirrors/jj

conflicts: add a simplify() method, taken from tree.rs

It seems generally useful to be able to simplify a conflict, and it's
not specific to merging trees, so let's move it to
`conflicts.rs`. Once we're done with the migration to tree-level
conflicts, I think `Conflict::simplify()` will remain but
`tree::simplify_conflict()` will be gone.

The tests I added there are quite similar to those of
`trivial_merge()`. I hope we can make `Conflict::simplify()` call
`trivial_merge()` later. I think it would also make sense to move
`trivial_merge()` onto `Conflict`, or at least have a
`Conflict::resolve_trivial()` calling `trivial_merge()`.
This commit is contained in:
Martin von Zweigbergk 2023-06-12 04:18:25 -07:00 committed by Martin von Zweigbergk
parent e5a28996b4
commit 1f1c6867c7
2 changed files with 90 additions and 16 deletions

View file

@ -60,6 +60,27 @@ impl<T> Conflict<T> {
pub fn set_add(&mut self, i: usize, value: T) {
self.adds[i] = value;
}
/// Remove pairs of entries that match in the removes and adds.
pub fn simplify(mut self) -> Self
where
T: PartialEq,
{
let mut add_index = 0;
while add_index < self.adds.len() {
let add = &self.adds[add_index];
add_index += 1;
for (remove_index, remove) in self.removes.iter().enumerate() {
if remove == add {
self.removes.remove(remove_index);
add_index -= 1;
self.adds.remove(add_index);
break;
}
}
}
self
}
}
impl Conflict<Option<TreeValue>> {
@ -644,4 +665,72 @@ mod tests {
);
test_roundtrip(&backend_conflict);
}
#[test]
fn test_simplify() {
fn c(removes: &[u32], adds: &[u32]) -> Conflict<u32> {
Conflict::new(removes.to_vec(), adds.to_vec())
}
// 1-way "conflict"
assert_eq!(c(&[], &[0]).simplify(), c(&[], &[0]));
// 3-way conflict
assert_eq!(c(&[0], &[0, 0]).simplify(), c(&[], &[0]));
assert_eq!(c(&[0], &[0, 1]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0], &[1, 0]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0], &[1, 1]).simplify(), c(&[0], &[1, 1]));
assert_eq!(c(&[0], &[1, 2]).simplify(), c(&[0], &[1, 2]));
// Irreducible 5-way conflict
assert_eq!(c(&[0, 0], &[0, 0, 0]).simplify(), c(&[], &[0]));
assert_eq!(c(&[0, 0], &[0, 0, 1]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0, 0], &[0, 1, 0]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0, 0], &[0, 1, 1]).simplify(), c(&[0], &[1, 1]));
assert_eq!(c(&[0, 0], &[0, 1, 2]).simplify(), c(&[0], &[1, 2]));
assert_eq!(c(&[0, 0], &[1, 0, 0]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0, 0], &[1, 0, 1]).simplify(), c(&[0], &[1, 1]));
assert_eq!(c(&[0, 0], &[1, 0, 2]).simplify(), c(&[0], &[1, 2]));
assert_eq!(c(&[0, 0], &[1, 1, 0]).simplify(), c(&[0], &[1, 1]));
assert_eq!(c(&[0, 0], &[1, 1, 1]).simplify(), c(&[0, 0], &[1, 1, 1]));
assert_eq!(c(&[0, 0], &[1, 1, 2]).simplify(), c(&[0, 0], &[1, 1, 2]));
assert_eq!(c(&[0, 0], &[1, 2, 0]).simplify(), c(&[0], &[1, 2]));
assert_eq!(c(&[0, 0], &[1, 2, 1]).simplify(), c(&[0, 0], &[1, 2, 1]));
assert_eq!(c(&[0, 0], &[1, 2, 2]).simplify(), c(&[0, 0], &[1, 2, 2]));
assert_eq!(c(&[0, 0], &[1, 2, 3]).simplify(), c(&[0, 0], &[1, 2, 3]));
assert_eq!(c(&[0, 1], &[0, 0, 0]).simplify(), c(&[1], &[0, 0]));
assert_eq!(c(&[0, 1], &[0, 0, 1]).simplify(), c(&[], &[0]));
assert_eq!(c(&[0, 1], &[0, 0, 2]).simplify(), c(&[1], &[0, 2]));
assert_eq!(c(&[0, 1], &[0, 1, 0]).simplify(), c(&[], &[0]));
assert_eq!(c(&[0, 1], &[0, 1, 1]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0, 1], &[0, 1, 2]).simplify(), c(&[], &[2]));
assert_eq!(c(&[0, 1], &[0, 2, 0]).simplify(), c(&[1], &[2, 0]));
assert_eq!(c(&[0, 1], &[0, 2, 1]).simplify(), c(&[], &[2]));
assert_eq!(c(&[0, 1], &[0, 2, 2]).simplify(), c(&[1], &[2, 2]));
assert_eq!(c(&[0, 1], &[0, 2, 3]).simplify(), c(&[1], &[2, 3]));
assert_eq!(c(&[0, 1], &[1, 0, 0]).simplify(), c(&[], &[0]));
assert_eq!(c(&[0, 1], &[1, 0, 1]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0, 1], &[1, 0, 2]).simplify(), c(&[], &[2]));
assert_eq!(c(&[0, 1], &[1, 1, 0]).simplify(), c(&[], &[1]));
assert_eq!(c(&[0, 1], &[1, 1, 1]).simplify(), c(&[0], &[1, 1]));
assert_eq!(c(&[0, 1], &[1, 1, 2]).simplify(), c(&[0], &[1, 2]));
assert_eq!(c(&[0, 1], &[1, 2, 0]).simplify(), c(&[], &[2]));
assert_eq!(c(&[0, 1], &[1, 2, 1]).simplify(), c(&[0], &[2, 1]));
assert_eq!(c(&[0, 1], &[1, 2, 2]).simplify(), c(&[0], &[2, 2]));
assert_eq!(c(&[0, 1], &[1, 2, 3]).simplify(), c(&[0], &[2, 3]));
assert_eq!(c(&[0, 1], &[2, 0, 0]).simplify(), c(&[1], &[2, 0]));
assert_eq!(c(&[0, 1], &[2, 0, 1]).simplify(), c(&[], &[2]));
assert_eq!(c(&[0, 1], &[2, 0, 2]).simplify(), c(&[1], &[2, 2]));
assert_eq!(c(&[0, 1], &[2, 0, 3]).simplify(), c(&[1], &[2, 3]));
assert_eq!(c(&[0, 1], &[2, 1, 0]).simplify(), c(&[], &[2]));
assert_eq!(c(&[0, 1], &[2, 1, 1]).simplify(), c(&[0], &[2, 1]));
assert_eq!(c(&[0, 1], &[2, 1, 2]).simplify(), c(&[0], &[2, 2]));
assert_eq!(c(&[0, 1], &[2, 1, 3]).simplify(), c(&[0], &[2, 3]));
assert_eq!(c(&[0, 1], &[2, 2, 0]).simplify(), c(&[1], &[2, 2]));
assert_eq!(c(&[0, 1], &[2, 2, 1]).simplify(), c(&[0], &[2, 2]));
assert_eq!(c(&[0, 1], &[2, 2, 2]).simplify(), c(&[0, 1], &[2, 2, 2]));
assert_eq!(c(&[0, 1], &[2, 2, 3]).simplify(), c(&[0, 1], &[2, 2, 3]));
assert_eq!(c(&[0, 1], &[2, 3, 0]).simplify(), c(&[1], &[2, 3]));
assert_eq!(c(&[0, 1], &[2, 3, 1]).simplify(), c(&[0], &[2, 3]));
assert_eq!(c(&[0, 1], &[2, 3, 2]).simplify(), c(&[0, 1], &[2, 3, 2]));
assert_eq!(c(&[0, 1], &[2, 3, 3]).simplify(), c(&[0, 1], &[2, 3, 3]));
assert_eq!(c(&[0, 1], &[2, 3, 4]).simplify(), c(&[0, 1], &[2, 3, 4]));
}
}

View file

@ -786,24 +786,9 @@ fn simplify_conflict(
}
}
// Remove pairs of entries that match in the removes and adds.
let mut add_index = 0;
while add_index < new_adds.len() {
let add = &new_adds[add_index];
add_index += 1;
for (remove_index, remove) in new_removes.iter().enumerate() {
if remove == add {
new_removes.remove(remove_index);
add_index -= 1;
new_adds.remove(add_index);
break;
}
}
}
// TODO: We should probably remove duplicate entries here too. So if we have
// {+A+A}, that would become just {+A}. Similarly {+B-A+B} would be just
// {+B-A}.
Ok(Conflict::new(new_removes, new_adds))
Ok(Conflict::new(new_removes, new_adds).simplify())
}