use std::collections::VecMap;
use std::iter::repeat;
pub struct BOM {
m: usize,
table: Vec<VecMap<usize>>
}
impl BOM {
pub fn new(pattern: &[u8]) -> Self {
let m = pattern.len();
let maxsym = *pattern.iter().max().expect("Expecting non-empty pattern.") as usize;
let mut table: Vec<VecMap<usize>> = Vec::with_capacity(m);
let mut suff: Vec<Option<usize>> = repeat(None).take(m + 1).collect();
for (j, &b) in pattern.iter().rev().enumerate() {
let i = j + 1;
let a = b as usize;
let mut delta = VecMap::with_capacity(maxsym);
delta.insert(a, i);
let mut k = suff[i - 1];
loop {
match k {
Some(k_) => {
if table[k_].contains_key(&a) {
break;
}
table[k_].insert(a, i);
k = suff[k_];
},
None => break
}
}
suff[i] = Some(match k {
Some(k) => *table[k].get(&a).unwrap(),
None => 0
});
table.push(delta);
}
BOM { m: m, table: table }
}
fn delta(&self, q: usize, a: u8) -> Option<usize> {
if q >= self.table.len() {
None
}
else {
match self.table[q].get(&(a as usize)) {
Some(&q) => Some(q),
None => None
}
}
}
pub fn find_all<'a>(&'a self, text: &'a [u8]) -> BOMMatches {
BOMMatches { bom: self, text: text, window: self.m }
}
}
pub struct BOMMatches<'a> {
bom: &'a BOM,
text: &'a [u8],
window: usize
}
impl<'a> Iterator for BOMMatches<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
while self.window <= self.text.len() {
let (mut q, mut j) = (Some(0), 1);
while j <= self.bom.m {
match q {
Some(q_) => {
q = self.bom.delta(q_, self.text[self.window - j]);
j += 1;
},
None => break
}
}
let i = self.window - self.bom.m;
self.window += self.bom.m - j + 2;
if q.is_some() {
return Some(i);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::BOM;
#[test]
fn test_delta() {
let pattern = b"qnnnannan"; let bom = BOM::new(pattern);
assert_eq!(bom.delta(0, b'n'), Some(1));
assert_eq!(bom.delta(1, b'a'), Some(2));
assert_eq!(bom.delta(2, b'n'), Some(3));
assert_eq!(bom.delta(3, b'n'), Some(4));
assert_eq!(bom.delta(4, b'a'), Some(5));
assert_eq!(bom.delta(5, b'n'), Some(6));
assert_eq!(bom.delta(6, b'n'), Some(7));
assert_eq!(bom.delta(7, b'n'), Some(8));
assert_eq!(bom.delta(8, b'q'), Some(9));
assert_eq!(bom.delta(0, b'a'), Some(2));
assert_eq!(bom.delta(0, b'q'), Some(9));
assert_eq!(bom.delta(1, b'n'), Some(4));
assert_eq!(bom.delta(1, b'q'), Some(9));
assert_eq!(bom.delta(4, b'n'), Some(8));
assert_eq!(bom.delta(4, b'q'), Some(9));
bom.delta(9, b'a');
}
}