use memchr::{memchr, memchr2, memchr3, Memchr};
#[inline]
pub fn find_byte(haystack: &[u8], needle: u8) -> Option<usize> {
memchr(needle, haystack)
}
#[inline]
pub fn find_bytes(haystack: &[u8], needles: &[u8]) -> Option<usize> {
match needles.len() {
0 => panic!("find_bytes requires at least one needle"),
1 => memchr(needles[0], haystack),
2 => memchr2(needles[0], needles[1], haystack),
3 => memchr3(needles[0], needles[1], needles[2], haystack),
_ => find_bytes_many(haystack, needles),
}
}
fn find_bytes_many(haystack: &[u8], needles: &[u8]) -> Option<usize> {
let mut lookup = [false; 256];
for &needle in needles {
lookup[needle as usize] = true;
}
haystack
.iter()
.position(|&byte| lookup[byte as usize])
}
#[inline]
pub fn count_byte(haystack: &[u8], needle: u8) -> usize {
Memchr::new(needle, haystack).count()
}
#[inline]
pub fn find_all_bytes(haystack: &[u8], needle: u8) -> impl Iterator<Item = usize> + '_ {
Memchr::new(needle, haystack)
}
#[inline]
pub fn rfind_byte(haystack: &[u8], needle: u8) -> Option<usize> {
memchr::memrchr(needle, haystack)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_byte_found() {
assert_eq!(find_byte(b"hello", b'e'), Some(1));
assert_eq!(find_byte(b"hello", b'h'), Some(0));
assert_eq!(find_byte(b"hello", b'o'), Some(4));
}
#[test]
fn test_find_byte_not_found() {
assert_eq!(find_byte(b"hello", b'x'), None);
assert_eq!(find_byte(b"", b'a'), None);
}
#[test]
fn test_find_bytes_single() {
assert_eq!(find_bytes(b"hello", &[b'e']), Some(1));
}
#[test]
fn test_find_bytes_double() {
assert_eq!(find_bytes(b"hello", &[b'x', b'e']), Some(1));
assert_eq!(find_bytes(b"hello", &[b'e', b'l']), Some(1));
}
#[test]
fn test_find_bytes_triple() {
assert_eq!(find_bytes(b"hello", &[b'x', b'y', b'o']), Some(4));
}
#[test]
fn test_find_bytes_many() {
assert_eq!(find_bytes(b"hello", &[b'w', b'x', b'y', b'o']), Some(4));
assert_eq!(find_bytes(b"hello", &[b'w', b'x', b'y', b'z']), None);
}
#[test]
#[should_panic(expected = "requires at least one needle")]
fn test_find_bytes_empty_panics() {
find_bytes(b"hello", &[]);
}
#[test]
fn test_count_byte() {
assert_eq!(count_byte(b"hello", b'l'), 2);
assert_eq!(count_byte(b"hello", b'x'), 0);
assert_eq!(count_byte(b"aaaaaa", b'a'), 6);
assert_eq!(count_byte(b"", b'a'), 0);
}
#[test]
fn test_find_all_bytes() {
let positions: Vec<_> = find_all_bytes(b"a.b.c", b'.').collect();
assert_eq!(positions, vec![1, 3]);
}
#[test]
fn test_rfind_byte() {
assert_eq!(rfind_byte(b"hello", b'l'), Some(3));
assert_eq!(rfind_byte(b"hello", b'h'), Some(0));
assert_eq!(rfind_byte(b"hello", b'x'), None);
}
#[test]
fn test_newline_operations() {
let text = b"line1\nline2\nline3\n";
assert_eq!(find_byte(text, b'\n'), Some(5));
assert_eq!(count_byte(text, b'\n'), 3);
assert_eq!(rfind_byte(text, b'\n'), Some(17));
}
#[test]
fn test_null_byte() {
let data = b"hello\0world";
assert_eq!(find_byte(data, b'\0'), Some(5));
}
}