use criterion::{black_box, criterion_group, criterion_main, Criterion};
use string_patterns::PatternMatch;
mod old {
pub fn pattern_match_ci(subject: &str, pattern: &str) -> bool {
match regex::Regex::new(&format!("(?i){pattern}")) {
Ok(re) => re.is_match(subject),
Err(_) => false,
}
}
}
struct Xorshift(u64);
impl Xorshift {
fn next_u64(&mut self) -> u64 {
let mut x = self.0;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.0 = x;
x
}
fn range(&mut self, n: usize) -> usize {
(self.next_u64() % n as u64) as usize
}
}
const NOISE_WORDS: &[&str] = &[
"connection", "established", "user", "request", "processed", "timeout", "retry",
"system", "memory", "usage", "cpu", "load", "average", "shutdown", "started",
"completed", "elapsed", "bytes", "sent", "received", "session", "token", "cache",
];
fn rand_words(rng: &mut Xorshift, n: usize) -> String {
(0..n)
.map(|_| NOISE_WORDS[rng.range(NOISE_WORDS.len())])
.collect::<Vec<_>>()
.join(" ")
}
fn gen_row(rng: &mut Xorshift) -> String {
if rng.range(5) == 0 {
format!("floating point error: {}", rand_words(rng, 4))
} else {
rand_words(rng, 6)
}
}
fn synthetic_rows(n: usize) -> Vec<String> {
let mut rng = Xorshift(0x9E3779B97F4A7C15);
(0..n).map(|_| gen_row(&mut rng)).collect()
}
const PATTERN: &str = r"\bfloat(ing)?.*?error";
fn bench_same_pattern_across_many_rows(c: &mut Criterion) {
let rows = synthetic_rows(2_000);
let mut group = c.benchmark_group("same_pattern_across_many_rows");
group.sample_size(50);
group.bench_function("old_uncached", |b| {
b.iter(|| {
rows.iter()
.filter(|row| old::pattern_match_ci(black_box(row.as_str()), black_box(PATTERN)))
.count()
})
});
group.bench_function("pattern_match_ci_now_cached", |b| {
b.iter(|| {
rows.iter()
.filter(|row| black_box(row.as_str()).pattern_match_ci(black_box(PATTERN)))
.count()
})
});
group.finish();
}
criterion_group!(benches, bench_same_pattern_across_many_rows);
criterion_main!(benches);