use memchr::{memchr, memchr2};
pub fn prefilter(needle: &str, haystack: &str) -> bool {
if needle.len() > haystack.len() {
return false;
}
prefilter_ascii(needle.as_bytes(), haystack.as_bytes()).is_some()
}
pub fn prefilter_with_typo(needle: &str, haystack: &str) -> bool {
if needle.len() > haystack.len() + 1 {
return false;
}
prefilter_ascii_with_typo(needle.as_bytes(), haystack.as_bytes()).is_some()
}
#[inline(always)]
fn prefilter_ascii(needle: &[u8], mut haystack: &[u8]) -> Option<()> {
let start = find_ascii_ignore_case(needle[0], &haystack[..haystack.len() - needle.len() + 1])?;
haystack = &haystack[(start + 1)..];
for &c in &needle[1..] {
let idx = find_ascii_ignore_case(c, haystack)? + 1;
haystack = &haystack[idx..];
}
Some(())
}
#[inline(always)]
fn prefilter_ascii_with_typo(needle: &[u8], mut haystack: &[u8]) -> Option<()> {
if needle.len() < 2 {
return Some(());
}
let (mut typos, start) = find_two_ascii_ignore_case(
needle[0],
needle[1],
&haystack[..haystack.len() - needle.len() + 2],
)?;
haystack = &haystack[(start + 1)..];
let mut idx = typos + 1;
while idx < needle.len() {
if let Some(match_idx) = find_ascii_ignore_case(needle[idx], haystack) {
haystack = &haystack[(match_idx + 1)..];
} else {
typos += 1;
if typos > 1 {
return None;
}
}
idx += 1;
}
Some(())
}
#[inline(always)]
fn find_two_ascii_ignore_case(c1: u8, c2: u8, haystack: &[u8]) -> Option<(usize, usize)> {
if let Some(idx) = find_ascii_ignore_case(c1, haystack) {
return Some((0, idx));
} else if let Some(idx) = find_ascii_ignore_case(c2, haystack) {
return Some((1, idx));
}
None
}
#[inline(always)]
fn find_ascii_ignore_case(c: u8, haystack: &[u8]) -> Option<usize> {
if c.is_ascii_lowercase() {
memchr2(c, c - 32, haystack)
} else {
memchr(c, haystack)
}
}