pub struct Horspool<'a> {
shift: Vec<usize>,
m: usize,
pattern: &'a [u8]
}
impl<'a> Horspool<'a> {
pub fn new(pattern: &'a [u8]) -> Self {
let m = pattern.len();
let mut shift = vec![m; 256];
for (j, &a) in pattern[..m-1].iter().enumerate() {
shift[a as usize] = m - 1 - j;
}
Horspool {
m: m, shift: shift, pattern: pattern
}
}
pub fn find_all<'b>(&'b self, text: &'b [u8]) -> HorspoolMatches {
HorspoolMatches {
horspool: self, text: text, n: text.len(),
last: self.m - 1,
pattern_last: self.pattern[self.m - 1]
}
}
}
pub struct HorspoolMatches<'a> {
horspool: &'a Horspool<'a>,
text: &'a [u8],
n: usize,
last: usize,
pattern_last: u8
}
impl<'a> Iterator for HorspoolMatches<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
loop {
while self.last < self.n
&& self.text[self.last] != self.pattern_last {
self.last += self.horspool.shift[self.text[self.last] as usize];
}
if self.last >= self.n {
return None;
}
let i = self.last - self.horspool.m + 1;
let j = self.last;
self.last += self.horspool.shift[self.pattern_last as usize];
if self.text[i..j] == self.horspool.pattern[..self.horspool.m-1] {
return Some(i);
}
}
}
}
#[cfg(test)]
mod tests {
use super::Horspool;
#[test]
fn test_shift() {
let pattern = b"AACB";
let horspool = Horspool::new(pattern);
assert_eq!(horspool.shift[b'A' as usize], 2);
assert_eq!(horspool.shift[b'C' as usize], 1);
assert_eq!(horspool.shift[b'B' as usize], 4);
assert_eq!(horspool.shift[b'X' as usize], 4);
}
}