use std::any::TypeId;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use ahash::AHasher;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use indexmap::IndexSet;
use std::hint::black_box;
#[derive(Clone)]
struct Key {
query_type: TypeId,
key_hash: u64,
#[allow(dead_code)]
debug_repr: Arc<str>,
}
impl Key {
fn new(id: u64) -> Self {
let mut hasher = AHasher::default();
id.hash(&mut hasher);
Self {
query_type: TypeId::of::<()>(),
key_hash: hasher.finish(),
debug_repr: Arc::from(format!("Key({})", id)),
}
}
}
impl Hash for Key {
fn hash<H: Hasher>(&self, state: &mut H) {
self.query_type.hash(state);
self.key_hash.hash(state);
}
}
impl PartialEq for Key {
fn eq(&self, other: &Self) -> bool {
self.query_type == other.query_type && self.key_hash == other.key_hash
}
}
impl Eq for Key {}
fn vec_cycle_check(stack: &mut Vec<Key>, key: Key) -> bool {
let has_cycle = stack.iter().any(|k| k == &key);
if has_cycle {
return true;
}
stack.push(key);
stack.pop();
false
}
fn indexset_cycle_check(stack: &mut IndexSet<Key, ahash::RandomState>, key: Key) -> bool {
let has_cycle = stack.contains(&key);
if has_cycle {
return true;
}
stack.insert(key);
stack.pop();
false
}
fn benchmark_stack_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("cycle_detection");
for depth in [1, 2, 4, 8, 16, 32] {
let keys: Vec<Key> = (0..depth).map(Key::new).collect();
let new_key = Key::new(depth);
group.bench_with_input(BenchmarkId::new("vec", depth), &depth, |b, _| {
let mut stack: Vec<Key> = keys.clone();
b.iter(|| {
vec_cycle_check(black_box(&mut stack), black_box(new_key.clone()));
stack.push(new_key.clone());
stack.pop();
});
});
group.bench_with_input(BenchmarkId::new("indexset", depth), &depth, |b, _| {
let mut stack: IndexSet<Key, ahash::RandomState> =
IndexSet::with_hasher(ahash::RandomState::new());
for key in &keys {
stack.insert(key.clone());
}
b.iter(|| {
indexset_cycle_check(black_box(&mut stack), black_box(new_key.clone()));
stack.insert(new_key.clone());
stack.pop();
});
});
}
group.finish();
}
criterion_group!(benches, benchmark_stack_operations);
criterion_main!(benches);