#[inline]
pub(crate) fn common_prefix_length(a: &[u8], b: &[u8]) -> usize {
const BLOCK: usize = 32;
let n = a.len().min(b.len());
let (a, b) = (&a[..n], &b[..n]);
let mut matched = 0;
for (x, y) in a
.as_chunks::<BLOCK>()
.0
.iter()
.zip(b.as_chunks::<BLOCK>().0)
{
if x != y {
break;
}
matched += BLOCK;
}
matched
+ a[matched..]
.iter()
.zip(&b[matched..])
.take_while(|(x, y)| x == y)
.count()
}
#[cfg(test)]
mod tests {
use super::*;
fn naive(a: &[u8], b: &[u8]) -> usize {
let mut i = 0;
while i < a.len() && i < b.len() && a[i] == b[i] {
i += 1;
}
i
}
#[test]
fn test_common_prefix_length_edge_cases() {
assert_eq!(common_prefix_length(b"", b""), 0);
assert_eq!(common_prefix_length(b"", b"abc"), 0);
assert_eq!(common_prefix_length(b"abc", b""), 0);
assert_eq!(common_prefix_length(b"abc", b"xyz"), 0);
assert_eq!(common_prefix_length(b"abc", b"abc"), 3);
assert_eq!(common_prefix_length(b"abc", b"abcdef"), 3);
assert_eq!(common_prefix_length(b"abcdef", b"abc"), 3);
}
#[test]
#[cfg_attr(miri, ignore)] fn test_common_prefix_length_around_block_boundaries() {
for len in [31, 32, 33, 63, 64, 65, 127, 128, 129, 1024] {
for mismatch in 0..=len {
let a = vec![b'x'; len];
let mut b = a.clone();
if mismatch < len {
b[mismatch] = b'y';
}
let expected = if mismatch < len { mismatch } else { len };
assert_eq!(
common_prefix_length(&a, &b),
expected,
"len={len} mismatch={mismatch}"
);
assert_eq!(common_prefix_length(&a, &b), naive(&a, &b));
}
}
}
#[test]
#[cfg_attr(miri, ignore)] fn test_common_prefix_length_unequal_lengths() {
for a_len in 0..80usize {
for b_len in 0..80usize {
let a = vec![b'x'; a_len];
let b = vec![b'x'; b_len];
assert_eq!(common_prefix_length(&a, &b), a_len.min(b_len));
assert_eq!(common_prefix_length(&a, &b), naive(&a, &b));
}
}
}
#[test]
fn test_common_prefix_length_matches_naive_on_varied_data() {
let a: Vec<u8> = (0..500u32).map(|i| (i * 7 % 251) as u8).collect();
for mismatch in 0..a.len() {
let mut b = a.clone();
b[mismatch] = b[mismatch].wrapping_add(1);
assert_eq!(common_prefix_length(&a, &b), naive(&a, &b));
assert_eq!(common_prefix_length(&a, &b), mismatch);
}
}
}