#![allow(missing_docs, unused_results)]
use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main};
use noyalib::simd::find_any_of;
fn scalar_find_any_of(haystack: &[u8], needles: &[u8]) -> Option<usize> {
for (i, &b) in haystack.iter().enumerate() {
if needles.contains(&b) {
return Some(i);
}
}
None
}
fn make_haystack(size: usize, dense: bool, needles: &[u8]) -> Vec<u8> {
let mut buf = vec![0u8; size];
for (i, slot) in buf.iter_mut().enumerate() {
*slot = 0x80 | ((i & 0x7F) as u8);
while needles.contains(slot) {
*slot = slot.wrapping_add(1);
}
}
if dense {
for i in (3..buf.len()).step_by(7) {
buf[i] = needles[i % needles.len()];
}
}
let last = buf.len().saturating_sub(1);
buf[last] = needles[0];
buf
}
fn bench_find_any_of(c: &mut Criterion) {
let arities: &[(&[u8], &str)] = &[
(b":", "arity_1_memchr"),
(b":\n#", "arity_3_memchr3"),
(b"[]{}:,#\n", "arity_8_swar"),
];
for &(needles, label) in arities {
let mut group = c.benchmark_group(format!("find_any_of/{label}"));
for size in [4 * 1024, 64 * 1024] {
for dense in [false, true] {
let haystack = make_haystack(size, dense, needles);
let density = if dense { "dense" } else { "sparse" };
let id = BenchmarkId::new(density, size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(
BenchmarkId::new(format!("{density}_simd"), size),
&haystack,
|b, haystack| {
b.iter(|| find_any_of(black_box(haystack), black_box(needles)));
},
);
group.bench_with_input(
BenchmarkId::new(format!("{density}_scalar"), size),
&haystack,
|b, haystack| {
b.iter(|| scalar_find_any_of(black_box(haystack), black_box(needles)));
},
);
let _ = id; }
}
group.finish();
}
}
criterion_group!(simd_benches, bench_find_any_of);
criterion_main!(simd_benches);