use std::iter::Enumerate;
#[derive(Copy)]
pub struct ShiftAnd {
m: usize,
masks: [u64; 256],
accept: u64
}
impl ShiftAnd {
pub fn new(pattern: &[u8]) -> ShiftAnd {
assert!(pattern.len() <= 64, "Expecting a pattern of at most 64 symbols.");
let (masks, accept) = masks(pattern);
ShiftAnd { m: pattern.len(), masks: masks, accept: accept }
}
pub fn find_all<'a, I: Iterator<Item=&'a u8>>(&'a self, text: I) -> ShiftAndMatches<I> {
ShiftAndMatches { shiftand: self, active: 0, text: text.enumerate() }
}
}
pub fn masks(pattern: &[u8]) -> ([u64; 256], u64) {
let mut masks = [0; 256];
let mut bit = 1;
for &c in pattern.iter() {
masks[c as usize] |= bit;
bit *= 2;
}
(masks, bit / 2)
}
pub struct ShiftAndMatches<'a, I: Iterator<Item=&'a u8>> {
shiftand: &'a ShiftAnd,
active: u64,
text: Enumerate<I>,
}
impl<'a, I: Iterator<Item=&'a u8>> Iterator for ShiftAndMatches<'a, I> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
for (i, &c) in self.text.by_ref() {
self.active = ((self.active << 1) | 1) & self.shiftand.masks[c as usize];
if self.active & self.shiftand.accept > 0 {
return Some(i - self.shiftand.m + 1);
}
}
None
}
}