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::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;
|
||||
|
||||
/// Hunt–McIlroy / Hunt–Szymanski LCS diff algorithm.
|
||||
|
|
@ -61,39 +61,29 @@ where
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let prefix_len = old_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 common_prefix_len = common_prefix_len(old, old_range.clone(), new, new_range.clone());
|
||||
let common_suffix_len = common_suffix_len(old, old_range.clone(), new, new_range.clone());
|
||||
|
||||
let maybe_table = make_table(
|
||||
old,
|
||||
prefix_len..(old_range.len() - suffix_len),
|
||||
common_prefix_len..(old_range.len() - common_suffix_len),
|
||||
new,
|
||||
prefix_len..(new_range.len() - suffix_len),
|
||||
common_prefix_len..(new_range.len() - common_suffix_len),
|
||||
deadline,
|
||||
);
|
||||
let mut old_idx = 0;
|
||||
let mut new_idx = 0;
|
||||
let new_len = new_range.len() - prefix_len - suffix_len;
|
||||
let old_len = old_range.len() - prefix_len - suffix_len;
|
||||
let new_len = new_range.len() - common_prefix_len - common_suffix_len;
|
||||
let old_len = old_range.len() - common_prefix_len - common_suffix_len;
|
||||
|
||||
if prefix_len > 0 {
|
||||
d.equal(old_range.start, new_range.start, prefix_len)?;
|
||||
if common_prefix_len > 0 {
|
||||
d.equal(old_range.start, new_range.start, common_prefix_len)?;
|
||||
}
|
||||
|
||||
if let Some(table) = maybe_table {
|
||||
while new_idx < new_len && old_idx < old_len {
|
||||
let old_orig_idx = old_range.start + prefix_len + old_idx;
|
||||
let new_orig_idx = new_range.start + prefix_len + new_idx;
|
||||
let old_orig_idx = old_range.start + common_prefix_len + old_idx;
|
||||
let new_orig_idx = new_range.start + common_prefix_len + new_idx;
|
||||
|
||||
if new[new_orig_idx] == old[old_orig_idx] {
|
||||
d.equal(old_orig_idx, new_orig_idx, 1)?;
|
||||
|
|
@ -110,34 +100,34 @@ where
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let old_orig_idx = old_range.start + prefix_len + old_idx;
|
||||
let new_orig_idx = new_range.start + prefix_len + new_idx;
|
||||
let old_orig_idx = old_range.start + common_prefix_len + old_idx;
|
||||
let new_orig_idx = new_range.start + common_prefix_len + new_idx;
|
||||
d.delete(old_orig_idx, old_len, new_orig_idx)?;
|
||||
d.insert(old_orig_idx, new_orig_idx, new_len)?;
|
||||
}
|
||||
|
||||
if old_idx < old_len {
|
||||
d.delete(
|
||||
old_range.start + prefix_len + old_idx,
|
||||
old_range.start + common_prefix_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;
|
||||
}
|
||||
|
||||
if new_idx < new_len {
|
||||
d.insert(
|
||||
old_range.start + prefix_len + old_idx,
|
||||
new_range.start + prefix_len + new_idx,
|
||||
old_range.start + common_prefix_len + old_idx,
|
||||
new_range.start + common_prefix_len + new_idx,
|
||||
new_len - new_idx,
|
||||
)?;
|
||||
}
|
||||
|
||||
if suffix_len > 0 {
|
||||
if common_suffix_len > 0 {
|
||||
d.equal(
|
||||
old_range.start + old_len + prefix_len,
|
||||
new_range.start + new_len + prefix_len,
|
||||
suffix_len,
|
||||
old_range.start + old_len + common_prefix_len,
|
||||
new_range.start + new_len + common_prefix_len,
|
||||
common_suffix_len,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
use std::ops::{Index, IndexMut, Range};
|
||||
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;
|
||||
|
||||
/// Myers' diff algorithm.
|
||||
|
|
@ -138,53 +138,6 @@ fn max_d(len1: usize, len2: usize) -> usize {
|
|||
(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)]
|
||||
fn split_at(range: Range<usize>, at: usize) -> (Range<usize>, Range<usize>) {
|
||||
(range.start..at, at..range.end)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,55 @@ where
|
|||
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]
|
||||
fn test_unique() {
|
||||
let u = unique(&vec!['a', 'b', 'c', 'd', 'd', 'b'], 0..6)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue