const CHUNK_SIZE: usize = 128 / 8;
trait EqCounter {
fn count_eq(self) -> usize;
}
impl<T, U> EqCounter for T
where
T: Iterator<Item = (U, U)>,
U: Eq,
{
#[inline]
fn count_eq(self) -> usize {
self.take_while(|(a, b)| a.eq(b)).count()
}
}
pub trait Finder<T: ?Sized> {
fn common<'a>(a: &'a T, b: &T) -> Option<&'a T>;
}
pub struct StringPrefix;
impl Finder<str> for StringPrefix {
fn common<'a>(a: &'a str, b: &str) -> Option<&'a str> {
let a_bytes = a.as_bytes();
let b_bytes = b.as_bytes();
let a_chunks = a_bytes.chunks_exact(CHUNK_SIZE);
let b_chunks = b_bytes.chunks_exact(CHUNK_SIZE);
let mut end = a_chunks.zip(b_chunks).count_eq();
end *= CHUNK_SIZE;
let a_rem = a_bytes.iter().skip(end);
let b_rem = b_bytes.iter().skip(end);
end += a_rem.zip(b_rem).count_eq();
while !a.is_char_boundary(end) {
end -= 1;
}
match end > 0 {
true => Some(unsafe { a.get_unchecked(..end) }),
false => None,
}
}
}
pub struct StringSuffix;
impl Finder<str> for StringSuffix {
fn common<'a>(a: &'a str, b: &str) -> Option<&'a str> {
let a_bytes = a.as_bytes();
let b_bytes = b.as_bytes();
let a_chunks = a_bytes.rchunks_exact(CHUNK_SIZE);
let b_chunks = b_bytes.rchunks_exact(CHUNK_SIZE);
let mut end = a_chunks.zip(b_chunks).count_eq();
end *= CHUNK_SIZE;
let a_rem = a_bytes.iter().rev().skip(end);
let b_rem = b_bytes.iter().rev().skip(end);
end += a_rem.zip(b_rem).count_eq();
let mut begin = a.len() - end;
while !a.is_char_boundary(begin) {
begin += 1;
}
match begin < a.len() {
true => Some(unsafe { a.get_unchecked(begin..) }),
false => None,
}
}
}
pub struct GenericPrefix;
impl<T: Eq> Finder<[T]> for GenericPrefix {
fn common<'a>(a: &'a [T], b: &[T]) -> Option<&'a [T]> {
let a_iter = a.iter();
let b_iter = b.iter();
let end = a_iter.zip(b_iter).count_eq();
match end > 0 {
true => Some(unsafe { a.get_unchecked(..end) }),
false => None,
}
}
}
pub struct GenericSuffix;
impl<T: Eq> Finder<[T]> for GenericSuffix {
fn common<'a>(a: &'a [T], b: &[T]) -> Option<&'a [T]> {
let a_iter = a.iter().rev();
let b_iter = b.iter().rev();
let end = a_iter.zip(b_iter).count_eq();
let begin = a.len() - end;
match begin < a.len() {
true => Some(unsafe { a.get_unchecked(begin..) }),
false => None,
}
}
}