Reuse common prefix / common suffix functions
This commit is contained in:
parent
b468bf94e3
commit
1a0aa9b142
3 changed files with 71 additions and 79 deletions
|
|
@ -6,7 +6,7 @@ use std::collections::BTreeMap;
|
||||||
use std::ops::{Index, Range};
|
use std::ops::{Index, Range};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::algorithms::utils::is_empty_range;
|
use crate::algorithms::utils::{common_prefix_len, common_suffix_len, is_empty_range};
|
||||||
use crate::algorithms::DiffHook;
|
use crate::algorithms::DiffHook;
|
||||||
|
|
||||||
/// Hunt–McIlroy / Hunt–Szymanski LCS diff algorithm.
|
/// Hunt–McIlroy / Hunt–Szymanski LCS diff algorithm.
|
||||||
|
|
@ -61,39 +61,29 @@ where
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix_len = old_range
|
let common_prefix_len = common_prefix_len(old, old_range.clone(), new, new_range.clone());
|
||||||
.clone()
|
let common_suffix_len = common_suffix_len(old, old_range.clone(), new, new_range.clone());
|
||||||
.zip(new_range.clone())
|
|
||||||
.take_while(|x| new[x.1] == old[x.0])
|
|
||||||
.count();
|
|
||||||
let suffix_len = old_range
|
|
||||||
.clone()
|
|
||||||
.rev()
|
|
||||||
.zip(new_range.clone().rev())
|
|
||||||
.take(old_range.len().min(new_range.len()) - prefix_len)
|
|
||||||
.take_while(|x| new[x.1] == old[x.0])
|
|
||||||
.count();
|
|
||||||
|
|
||||||
let maybe_table = make_table(
|
let maybe_table = make_table(
|
||||||
old,
|
old,
|
||||||
prefix_len..(old_range.len() - suffix_len),
|
common_prefix_len..(old_range.len() - common_suffix_len),
|
||||||
new,
|
new,
|
||||||
prefix_len..(new_range.len() - suffix_len),
|
common_prefix_len..(new_range.len() - common_suffix_len),
|
||||||
deadline,
|
deadline,
|
||||||
);
|
);
|
||||||
let mut old_idx = 0;
|
let mut old_idx = 0;
|
||||||
let mut new_idx = 0;
|
let mut new_idx = 0;
|
||||||
let new_len = new_range.len() - prefix_len - suffix_len;
|
let new_len = new_range.len() - common_prefix_len - common_suffix_len;
|
||||||
let old_len = old_range.len() - prefix_len - suffix_len;
|
let old_len = old_range.len() - common_prefix_len - common_suffix_len;
|
||||||
|
|
||||||
if prefix_len > 0 {
|
if common_prefix_len > 0 {
|
||||||
d.equal(old_range.start, new_range.start, prefix_len)?;
|
d.equal(old_range.start, new_range.start, common_prefix_len)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(table) = maybe_table {
|
if let Some(table) = maybe_table {
|
||||||
while new_idx < new_len && old_idx < old_len {
|
while new_idx < new_len && old_idx < old_len {
|
||||||
let old_orig_idx = old_range.start + prefix_len + old_idx;
|
let old_orig_idx = old_range.start + common_prefix_len + old_idx;
|
||||||
let new_orig_idx = new_range.start + prefix_len + new_idx;
|
let new_orig_idx = new_range.start + common_prefix_len + new_idx;
|
||||||
|
|
||||||
if new[new_orig_idx] == old[old_orig_idx] {
|
if new[new_orig_idx] == old[old_orig_idx] {
|
||||||
d.equal(old_orig_idx, new_orig_idx, 1)?;
|
d.equal(old_orig_idx, new_orig_idx, 1)?;
|
||||||
|
|
@ -110,34 +100,34 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let old_orig_idx = old_range.start + prefix_len + old_idx;
|
let old_orig_idx = old_range.start + common_prefix_len + old_idx;
|
||||||
let new_orig_idx = new_range.start + prefix_len + new_idx;
|
let new_orig_idx = new_range.start + common_prefix_len + new_idx;
|
||||||
d.delete(old_orig_idx, old_len, new_orig_idx)?;
|
d.delete(old_orig_idx, old_len, new_orig_idx)?;
|
||||||
d.insert(old_orig_idx, new_orig_idx, new_len)?;
|
d.insert(old_orig_idx, new_orig_idx, new_len)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if old_idx < old_len {
|
if old_idx < old_len {
|
||||||
d.delete(
|
d.delete(
|
||||||
old_range.start + prefix_len + old_idx,
|
old_range.start + common_prefix_len + old_idx,
|
||||||
old_len - old_idx,
|
old_len - old_idx,
|
||||||
new_range.start + prefix_len + new_idx,
|
new_range.start + common_prefix_len + new_idx,
|
||||||
)?;
|
)?;
|
||||||
old_idx += old_len - old_idx;
|
old_idx += old_len - old_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_idx < new_len {
|
if new_idx < new_len {
|
||||||
d.insert(
|
d.insert(
|
||||||
old_range.start + prefix_len + old_idx,
|
old_range.start + common_prefix_len + old_idx,
|
||||||
new_range.start + prefix_len + new_idx,
|
new_range.start + common_prefix_len + new_idx,
|
||||||
new_len - new_idx,
|
new_len - new_idx,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if suffix_len > 0 {
|
if common_suffix_len > 0 {
|
||||||
d.equal(
|
d.equal(
|
||||||
old_range.start + old_len + prefix_len,
|
old_range.start + old_len + common_prefix_len,
|
||||||
new_range.start + new_len + prefix_len,
|
new_range.start + new_len + common_prefix_len,
|
||||||
suffix_len,
|
common_suffix_len,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
use std::ops::{Index, IndexMut, Range};
|
use std::ops::{Index, IndexMut, Range};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::algorithms::utils::is_empty_range;
|
use crate::algorithms::utils::{common_prefix_len, common_suffix_len, is_empty_range};
|
||||||
use crate::algorithms::DiffHook;
|
use crate::algorithms::DiffHook;
|
||||||
|
|
||||||
/// Myers' diff algorithm.
|
/// Myers' diff algorithm.
|
||||||
|
|
@ -138,53 +138,6 @@ fn max_d(len1: usize, len2: usize) -> usize {
|
||||||
(len1 + len2 + 1) / 2 + 1
|
(len1 + len2 + 1) / 2 + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common_prefix_len<Old, New>(
|
|
||||||
old: &Old,
|
|
||||||
old_range: Range<usize>,
|
|
||||||
new: &New,
|
|
||||||
new_range: Range<usize>,
|
|
||||||
) -> usize
|
|
||||||
where
|
|
||||||
Old: Index<usize> + ?Sized,
|
|
||||||
New: Index<usize> + ?Sized,
|
|
||||||
New::Output: PartialEq<Old::Output>,
|
|
||||||
{
|
|
||||||
if is_empty_range(&old_range) || is_empty_range(&new_range) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
new_range
|
|
||||||
.zip(old_range)
|
|
||||||
.take_while(
|
|
||||||
#[inline(always)]
|
|
||||||
|x| new[x.0] == old[x.1],
|
|
||||||
)
|
|
||||||
.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn common_suffix_len<Old, New>(
|
|
||||||
old: &Old,
|
|
||||||
old_range: Range<usize>,
|
|
||||||
new: &New,
|
|
||||||
new_range: Range<usize>,
|
|
||||||
) -> usize
|
|
||||||
where
|
|
||||||
Old: Index<usize> + ?Sized,
|
|
||||||
New: Index<usize> + ?Sized,
|
|
||||||
New::Output: PartialEq<Old::Output>,
|
|
||||||
{
|
|
||||||
if is_empty_range(&old_range) || is_empty_range(&new_range) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
new_range
|
|
||||||
.rev()
|
|
||||||
.zip(old_range.rev())
|
|
||||||
.take_while(
|
|
||||||
#[inline(always)]
|
|
||||||
|x| new[x.0] == old[x.1],
|
|
||||||
)
|
|
||||||
.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn split_at(range: Range<usize>, at: usize) -> (Range<usize>, Range<usize>) {
|
fn split_at(range: Range<usize>, at: usize) -> (Range<usize>, Range<usize>) {
|
||||||
(range.start..at, at..range.end)
|
(range.start..at, at..range.end)
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,55 @@ where
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given two lookups and ranges calculates the length of the common prefix.
|
||||||
|
pub fn common_prefix_len<Old, New>(
|
||||||
|
old: &Old,
|
||||||
|
old_range: Range<usize>,
|
||||||
|
new: &New,
|
||||||
|
new_range: Range<usize>,
|
||||||
|
) -> usize
|
||||||
|
where
|
||||||
|
Old: Index<usize> + ?Sized,
|
||||||
|
New: Index<usize> + ?Sized,
|
||||||
|
New::Output: PartialEq<Old::Output>,
|
||||||
|
{
|
||||||
|
if is_empty_range(&old_range) || is_empty_range(&new_range) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
new_range
|
||||||
|
.zip(old_range)
|
||||||
|
.take_while(
|
||||||
|
#[inline(always)]
|
||||||
|
|x| new[x.0] == old[x.1],
|
||||||
|
)
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given two lookups and ranges calculates the length of common suffix.
|
||||||
|
pub fn common_suffix_len<Old, New>(
|
||||||
|
old: &Old,
|
||||||
|
old_range: Range<usize>,
|
||||||
|
new: &New,
|
||||||
|
new_range: Range<usize>,
|
||||||
|
) -> usize
|
||||||
|
where
|
||||||
|
Old: Index<usize> + ?Sized,
|
||||||
|
New: Index<usize> + ?Sized,
|
||||||
|
New::Output: PartialEq<Old::Output>,
|
||||||
|
{
|
||||||
|
if is_empty_range(&old_range) || is_empty_range(&new_range) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
new_range
|
||||||
|
.rev()
|
||||||
|
.zip(old_range.rev())
|
||||||
|
.take_while(
|
||||||
|
#[inline(always)]
|
||||||
|
|x| new[x.0] == old[x.1],
|
||||||
|
)
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unique() {
|
fn test_unique() {
|
||||||
let u = unique(&vec!['a', 'b', 'c', 'd', 'd', 'b'], 0..6)
|
let u = unique(&vec!['a', 'b', 'c', 'd', 'd', 'b'], 0..6)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue