use aho_corasick::{AcAutomaton, Sparse};
use memchr::memchr;
#[derive(Clone, Debug)]
pub enum Prefix {
Empty,
Single(u8),
Singles(Vec<bool>),
Automaton(AcAutomaton<Sparse>),
}
impl Prefix {
pub fn new(pfxs: Vec<String>) -> Prefix {
if pfxs.len() == 0 || pfxs[0].len() == 0 {
Prefix::Empty
} else if pfxs.len() == 1 && pfxs[0].len() == 1 {
Prefix::Single(pfxs[0].as_bytes()[0])
} else if pfxs.len() >= 2 && pfxs.iter().all(|s| s.len() == 1) {
let mut set = vec![false; 256];
for p in pfxs {
set[p.as_bytes()[0] as usize] = true;
}
Prefix::Singles(set)
} else {
Prefix::Automaton(AcAutomaton::with_transitions(pfxs))
}
}
pub fn find(&self, haystack: &str) -> Option<(usize, usize)> {
use self::Prefix::*;
match *self {
Empty => Some((0, 0)),
Single(b) => memchr(b, haystack.as_bytes()).map(|i| (i, i+1)),
Singles(ref pats) => find_singles(pats, haystack.as_bytes()),
Automaton(ref aut) => {
aut.find(haystack).next().map(|m| (m.start, m.end))
}
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
match *self {
Prefix::Empty => 0,
Prefix::Single(_) => 1,
Prefix::Singles(ref pats) => pats.len(),
Prefix::Automaton(ref aut) => aut.len(),
}
}
}
fn find_singles(pats: &[bool], haystack: &[u8]) -> Option<(usize, usize)> {
for (hi, &b) in haystack.iter().enumerate() {
if pats[b as usize] {
return Some((hi, hi+1));
}
}
None
}