diff --git a/src/algorithms/lcs.rs b/src/algorithms/lcs.rs index e48e550..bc6ad6f 100644 --- a/src/algorithms/lcs.rs +++ b/src/algorithms/lcs.rs @@ -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, )?; } diff --git a/src/algorithms/myers.rs b/src/algorithms/myers.rs index 5e475ea..08176b1 100644 --- a/src/algorithms/myers.rs +++ b/src/algorithms/myers.rs @@ -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: &Old, - old_range: Range, - new: &New, - new_range: Range, -) -> usize -where - Old: Index + ?Sized, - New: Index + ?Sized, - New::Output: PartialEq, -{ - 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: &Old, - old_range: Range, - new: &New, - new_range: Range, -) -> usize -where - Old: Index + ?Sized, - New: Index + ?Sized, - New::Output: PartialEq, -{ - 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, at: usize) -> (Range, Range) { (range.start..at, at..range.end) diff --git a/src/algorithms/utils.rs b/src/algorithms/utils.rs index 192aa04..622b2ee 100644 --- a/src/algorithms/utils.rs +++ b/src/algorithms/utils.rs @@ -93,6 +93,55 @@ where rv } +/// Given two lookups and ranges calculates the length of the common prefix. +pub fn common_prefix_len( + old: &Old, + old_range: Range, + new: &New, + new_range: Range, +) -> usize +where + Old: Index + ?Sized, + New: Index + ?Sized, + New::Output: PartialEq, +{ + 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: &Old, + old_range: Range, + new: &New, + new_range: Range, +) -> usize +where + Old: Index + ?Sized, + New: Index + ?Sized, + New::Output: PartialEq, +{ + 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)