Remove LCS
This commit is contained in:
parent
7f6973389f
commit
08910f1454
2 changed files with 0 additions and 166 deletions
|
|
@ -1,165 +0,0 @@
|
|||
//! LCS diff algorithm.
|
||||
//!
|
||||
//! * time: `O((NM)D log (M)D)`
|
||||
//! * space `O(MN)`
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::{Index, Range};
|
||||
|
||||
use crate::tokenizer::token::Token;
|
||||
|
||||
use super::raw_operation::RawOperation;
|
||||
use super::utils::{common_prefix_len, common_suffix_len};
|
||||
|
||||
/// LCS diff algorithm.
|
||||
/// Copied from https://github.com/mitsuhiko/similar/blob/7e15c44de11a1cd61e1149189929e189ef977fd8/src/algorithms/lcs.rs
|
||||
pub fn diff(old: &[Token], new: &[Token]) -> Vec<RawOperation> {
|
||||
let common_prefix_len = common_prefix_len(old, 0..old.len(), new, 0..new.len());
|
||||
let common_suffix_len = common_suffix_len(
|
||||
old,
|
||||
common_prefix_len..old.len(),
|
||||
new,
|
||||
common_prefix_len..new.len(),
|
||||
);
|
||||
|
||||
let maybe_table = make_table(
|
||||
old,
|
||||
common_prefix_len..(old.len() - common_suffix_len),
|
||||
new,
|
||||
common_prefix_len..(new.len() - common_suffix_len),
|
||||
);
|
||||
let mut old_idx = 0;
|
||||
let mut new_idx = 0;
|
||||
let new_len = new.len() - common_prefix_len - common_suffix_len;
|
||||
let old_len = old.len() - common_prefix_len - common_suffix_len;
|
||||
|
||||
let mut result: Vec<RawOperation> = Vec::new();
|
||||
if common_prefix_len > 0 {
|
||||
result.push(RawOperation::Equal(old[0..common_prefix_len].to_vec()));
|
||||
}
|
||||
|
||||
if let Some(table) = maybe_table {
|
||||
while new_idx < new_len && old_idx < old_len {
|
||||
let old_orig_idx = common_prefix_len + old_idx;
|
||||
let new_orig_idx = common_prefix_len + new_idx;
|
||||
|
||||
if new[new_orig_idx] == old[old_orig_idx] {
|
||||
result.push(RawOperation::Equal(vec![old[old_orig_idx].clone()]));
|
||||
old_idx += 1;
|
||||
new_idx += 1;
|
||||
} else if table.get(&(new_idx, old_idx + 1)).unwrap_or(&0)
|
||||
>= table.get(&(new_idx + 1, old_idx)).unwrap_or(&0)
|
||||
{
|
||||
result.push(RawOperation::Delete(vec![old[old_orig_idx].clone()]));
|
||||
old_idx += 1;
|
||||
} else {
|
||||
result.push(RawOperation::Insert(vec![new[new_orig_idx].clone()]));
|
||||
new_idx += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let old_orig_idx = common_prefix_len + old_idx;
|
||||
let new_orig_idx = common_prefix_len + new_idx;
|
||||
|
||||
result.push(RawOperation::Delete(
|
||||
old[old_orig_idx..old_orig_idx + old_len].to_vec(),
|
||||
));
|
||||
result.push(RawOperation::Insert(
|
||||
new[new_orig_idx..new_orig_idx + new_len].to_vec(),
|
||||
));
|
||||
}
|
||||
|
||||
if old_idx < old_len {
|
||||
result.push(RawOperation::Delete(
|
||||
old[common_prefix_len + old_idx..common_prefix_len + old_len].to_vec(),
|
||||
));
|
||||
old_idx += old_len - old_idx;
|
||||
}
|
||||
|
||||
if new_idx < new_len {
|
||||
result.push(RawOperation::Insert(
|
||||
new[common_prefix_len + new_idx..common_prefix_len + new_len].to_vec(),
|
||||
));
|
||||
}
|
||||
|
||||
if common_suffix_len > 0 {
|
||||
result.push(RawOperation::Equal(
|
||||
old[old_len + common_prefix_len..old_len + common_prefix_len + common_suffix_len]
|
||||
.to_vec(),
|
||||
));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn make_table<Old, New>(
|
||||
old: &Old,
|
||||
old_range: Range<usize>,
|
||||
new: &New,
|
||||
new_range: Range<usize>,
|
||||
) -> Option<BTreeMap<(usize, usize), u32>>
|
||||
where
|
||||
Old: Index<usize> + ?Sized,
|
||||
New: Index<usize> + ?Sized,
|
||||
New::Output: PartialEq<Old::Output>,
|
||||
{
|
||||
let old_len = old_range.len();
|
||||
let new_len = new_range.len();
|
||||
let mut table = BTreeMap::new();
|
||||
|
||||
for i in (0..new_len).rev() {
|
||||
for j in (0..old_len).rev() {
|
||||
let val = if new[i] == old[j] {
|
||||
table.get(&(i + 1, j + 1)).unwrap_or(&0) + 1
|
||||
} else {
|
||||
*table
|
||||
.get(&(i + 1, j))
|
||||
.unwrap_or(&0)
|
||||
.max(table.get(&(i, j + 1)).unwrap_or(&0))
|
||||
};
|
||||
if val > 0 {
|
||||
table.insert((i, j), val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(table)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn test_table() {
|
||||
let table = make_table(&vec![2, 3], 0..2, &vec![0, 1, 2], 0..3).unwrap();
|
||||
let expected = {
|
||||
let mut m = BTreeMap::new();
|
||||
m.insert((1, 0), 1);
|
||||
m.insert((0, 0), 1);
|
||||
m.insert((2, 0), 1);
|
||||
m
|
||||
};
|
||||
assert_eq!(table, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_examples() {
|
||||
assert_eq!(diff(&[], &[]), vec![]);
|
||||
assert_eq!(
|
||||
diff(&[Token::new("a".to_string(), "a".to_string())], &[]),
|
||||
vec![RawOperation::Delete(vec![Token::new(
|
||||
"a".to_string(),
|
||||
"a".to_string()
|
||||
)])]
|
||||
);
|
||||
assert_eq!(
|
||||
diff(&[], &[Token::new("a".to_string(), "a".to_string())]),
|
||||
vec![RawOperation::Insert(vec![Token::new(
|
||||
"a".to_string(),
|
||||
"a".to_string()
|
||||
)])]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
pub mod lcs;
|
||||
pub mod myers;
|
||||
pub mod raw_operation;
|
||||
mod utils;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue