Performance improvements for LCS and inline highlighting (#16)
This commit is contained in:
parent
bdb1f7a644
commit
45bcb3943c
2 changed files with 34 additions and 13 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! * time: `O((NM)D log (M)D)`
|
//! * time: `O((NM)D log (M)D)`
|
||||||
//! * space `O(MN)`
|
//! * space `O(MN)`
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::ops::{Index, Range};
|
use std::ops::{Index, Range};
|
||||||
|
|
||||||
use crate::algorithms::DiffHook;
|
use crate::algorithms::DiffHook;
|
||||||
|
|
@ -66,7 +67,9 @@ where
|
||||||
d.equal(old_orig_idx, new_orig_idx, 1)?;
|
d.equal(old_orig_idx, new_orig_idx, 1)?;
|
||||||
old_idx += 1;
|
old_idx += 1;
|
||||||
new_idx += 1;
|
new_idx += 1;
|
||||||
} else if table[new_idx][old_idx + 1] >= table[new_idx + 1][old_idx] {
|
} else if table.get(&(new_idx, old_idx + 1)).map_or(0, |&x| x)
|
||||||
|
>= table.get(&(new_idx + 1, old_idx)).map_or(0, |&x| x)
|
||||||
|
{
|
||||||
d.delete(old_orig_idx, 1, new_orig_idx)?;
|
d.delete(old_orig_idx, 1, new_orig_idx)?;
|
||||||
old_idx += 1;
|
old_idx += 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -117,7 +120,7 @@ fn make_table<Old, New>(
|
||||||
old_range: Range<usize>,
|
old_range: Range<usize>,
|
||||||
new: &New,
|
new: &New,
|
||||||
new_range: Range<usize>,
|
new_range: Range<usize>,
|
||||||
) -> Vec<Vec<u32>>
|
) -> BTreeMap<(usize, usize), u32>
|
||||||
where
|
where
|
||||||
Old: Index<usize> + ?Sized,
|
Old: Index<usize> + ?Sized,
|
||||||
New: Index<usize> + ?Sized,
|
New: Index<usize> + ?Sized,
|
||||||
|
|
@ -125,17 +128,20 @@ where
|
||||||
{
|
{
|
||||||
let old_len = old_range.len();
|
let old_len = old_range.len();
|
||||||
let new_len = new_range.len();
|
let new_len = new_range.len();
|
||||||
let mut table = vec![vec![0; old_len + 1]; new_len + 1];
|
let mut table = BTreeMap::new();
|
||||||
|
|
||||||
for i in 0..new_len {
|
for i in (0..new_len).rev() {
|
||||||
let i = new_len - i - 1;
|
for j in (0..old_len).rev() {
|
||||||
table[i][old_len] = 0;
|
let val = if new[i] == old[j] {
|
||||||
for j in 0..old_len {
|
table.get(&(i + 1, j + 1)).map_or(0, |&x| x) + 1
|
||||||
let j = old_len - j - 1;
|
|
||||||
table[i][j] = if new[i] == old[j] {
|
|
||||||
table[i + 1][j + 1] + 1
|
|
||||||
} else {
|
} else {
|
||||||
table[i + 1][j].max(table[i][j + 1])
|
table
|
||||||
|
.get(&(i + 1, j))
|
||||||
|
.map_or(0, |&x| x)
|
||||||
|
.max(table.get(&(i, j + 1)).map_or(0, |&x| x))
|
||||||
|
};
|
||||||
|
if val > 0 {
|
||||||
|
table.insert((i, j), val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +152,13 @@ where
|
||||||
#[test]
|
#[test]
|
||||||
fn test_table() {
|
fn test_table() {
|
||||||
let table = make_table(&vec![2, 3], 0..2, &vec![0, 1, 2], 0..3);
|
let table = make_table(&vec![2, 3], 0..2, &vec![0, 1, 2], 0..3);
|
||||||
let expected = vec![vec![1, 0, 0], vec![1, 0, 0], vec![1, 0, 0], vec![0, 0, 0]];
|
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);
|
assert_eq!(table, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ use crate::{capture_diff, get_diff_ratio};
|
||||||
|
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
|
use super::utils::upper_seq_ratio;
|
||||||
|
|
||||||
struct MultiLookup<'bufs, 's, T: DiffableStr + ?Sized> {
|
struct MultiLookup<'bufs, 's, T: DiffableStr + ?Sized> {
|
||||||
strings: &'bufs [&'s T],
|
strings: &'bufs [&'s T],
|
||||||
seqs: Vec<(&'s T, usize, usize)>,
|
seqs: Vec<(&'s T, usize, usize)>,
|
||||||
|
|
@ -184,6 +186,8 @@ impl<'s, T: DiffableStr + ?Sized> fmt::Display for InlineChange<'s, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MIN_RATIO: f32 = 0.5;
|
||||||
|
|
||||||
pub(crate) fn iter_inline_changes<'x, 'diff, 'old, 'new, 'bufs, T>(
|
pub(crate) fn iter_inline_changes<'x, 'diff, 'old, 'new, 'bufs, T>(
|
||||||
diff: &'diff TextDiff<'old, 'new, 'bufs, T>,
|
diff: &'diff TextDiff<'old, 'new, 'bufs, T>,
|
||||||
op: &DiffOp,
|
op: &DiffOp,
|
||||||
|
|
@ -204,6 +208,11 @@ where
|
||||||
let mut new_index = new_range.start;
|
let mut new_index = new_range.start;
|
||||||
let old_slices = &diff.old_slices()[old_range];
|
let old_slices = &diff.old_slices()[old_range];
|
||||||
let new_slices = &diff.new_slices()[new_range];
|
let new_slices = &diff.new_slices()[new_range];
|
||||||
|
|
||||||
|
if upper_seq_ratio(old_slices, new_slices) < MIN_RATIO {
|
||||||
|
return Box::new(diff.iter_changes(op).map(|x| x.into())) as Box<dyn Iterator<Item = _>>;
|
||||||
|
}
|
||||||
|
|
||||||
let old_lookup = MultiLookup::new(old_slices);
|
let old_lookup = MultiLookup::new(old_slices);
|
||||||
let new_lookup = MultiLookup::new(new_slices);
|
let new_lookup = MultiLookup::new(new_slices);
|
||||||
|
|
||||||
|
|
@ -215,7 +224,7 @@ where
|
||||||
0..new_lookup.len(),
|
0..new_lookup.len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if get_diff_ratio(&ops, old_lookup.len(), new_lookup.len()) < 0.5 {
|
if get_diff_ratio(&ops, old_lookup.len(), new_lookup.len()) < MIN_RATIO {
|
||||||
return Box::new(diff.iter_changes(op).map(|x| x.into())) as Box<dyn Iterator<Item = _>>;
|
return Box::new(diff.iter_changes(op).map(|x| x.into())) as Box<dyn Iterator<Item = _>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue