use super::{LevState, LevWeights};
use std::cmp::min;
#[inline]
pub fn try_levenshtein_iter<I, T, D>(a: I, b: I, limit: u32) -> Option<u32>
where
I: IntoIterator<IntoIter = D>,
D: DoubleEndedIterator<Item = T> + Clone,
T: PartialEq,
{
let state = LevState::new(a.into_iter(), b.into_iter());
let LevState {
a_iter,
b_iter,
a_diff_len: a_len,
b_diff_len: b_len,
} = state;
if b_len == 0 {
if a_len < limit {
return Some(a_len);
} else {
return None;
}
}
if b_len - a_len > limit {
return None;
}
let mut work_vec: Vec<u32> = (1..=b_len).collect();
let mut tmp_res = b_len;
for (i, a_item) in a_iter.enumerate().take_while(|&(i, _)| i < a_len as usize) {
let mut sub_base = i as u32;
tmp_res = sub_base + 1;
for (j, b_item) in b_iter
.clone()
.enumerate()
.take_while(|&(j, _)| j < b_len as usize)
{
let del_base = work_vec[j];
if a_item == b_item {
tmp_res = min(min(tmp_res, del_base) + 1, sub_base);
} else {
tmp_res = min(min(tmp_res, del_base), sub_base) + 1;
}
sub_base = del_base;
work_vec[j] = tmp_res;
}
if tmp_res > limit {
return None;
}
}
Some(tmp_res)
}
#[inline]
pub fn levenshtein_weight_iter<I, T, D>(a: I, b: I, limit: u32, weights: &LevWeights) -> u32
where
I: IntoIterator<IntoIter = D>,
D: DoubleEndedIterator<Item = T> + Clone,
T: PartialEq,
{
try_levenshtein_weight_iter(a, b, limit, weights).unwrap_or(limit)
}
#[inline]
pub fn try_levenshtein_weight_iter<I, T, D>(
a: I,
b: I,
limit: u32,
weights: &LevWeights,
) -> Option<u32>
where
I: IntoIterator<IntoIter = D>,
D: DoubleEndedIterator<Item = T> + Clone,
T: PartialEq,
{
let mut weights = weights.clone();
let state = LevState::new_weights(a.into_iter(), b.into_iter(), &mut weights);
let LevState {
a_iter,
b_iter,
a_diff_len: a_len,
b_diff_len: b_len,
} = state;
let LevWeights {
insertion: w_ins,
deletion: w_del,
substitution: w_sub,
} = weights;
if b_len == 0 {
let tmp = a_len * w_del;
if tmp < limit {
return Some(tmp);
} else {
return None;
}
}
if b_len - a_len > limit {
return None;
}
let equal_weights = w_ins == w_del && w_del == w_sub;
let mut work_vec: Vec<u32> = (w_ins..=(b_len * w_ins)).step_by(w_ins as usize).collect();
let mut tmp_res = b_len * w_ins;
for (i, a_item) in a_iter.enumerate().take_while(|&(i, _)| i < a_len as usize) {
let mut sub_base = i as u32 * w_del;
tmp_res = sub_base + w_del;
for (j, b_item) in b_iter
.clone()
.enumerate()
.take_while(|&(j, _)| j < b_len as usize)
{
let del_base = work_vec[j];
if equal_weights {
if a_item == b_item {
tmp_res = min(min(tmp_res, del_base) + w_ins, sub_base);
} else {
tmp_res = min(min(tmp_res, del_base), sub_base) + w_ins;
}
} else if a_item == b_item {
tmp_res = min(min(tmp_res + w_ins, del_base + w_del), sub_base);
} else {
tmp_res = min(min(tmp_res + w_ins, del_base + w_del), sub_base + w_sub);
}
sub_base = del_base;
work_vec[j] = tmp_res;
}
if tmp_res > limit {
return None;
}
}
Some(tmp_res)
}