use renew_ecs::{Entities, Store};
use renew_memory::{CountingAllocator, counters};
#[global_allocator]
static ALLOCATOR: CountingAllocator = CountingAllocator;
const SLOTS: u32 = 64;
#[test]
#[cfg_attr(
feature = "sanitized",
ignore = "allocation counting is invalid under instrumented allocators"
)]
fn the_steady_state_costs_the_heap_nothing_except_the_ordered_mutable_walk() {
let mut entities = Entities::new();
let mut store: Store<u32> = Store::new();
let mut live: Vec<_> = Vec::with_capacity(SLOTS as usize);
for value in 0..SLOTS {
let entity = entities.spawn();
store.insert(entity.index(), value);
live.push(entity);
}
assert_eq!(store.len(), SLOTS as usize, "the fixture really filled");
let mut seen = 0u64;
let verdict = counters::quiet_window(5, || {
for _ in 0..8 {
for (slot, value) in store.iter() {
seen = seen
.wrapping_add(u64::from(slot))
.wrapping_add(u64::from(*value));
}
for value in store.iter_unordered() {
seen = seen.wrapping_add(u64::from(*value));
}
for entity in &live {
if let Some(value) = store.get(entity.index()) {
seen = seen.wrapping_add(u64::from(*value));
}
}
}
});
verdict.expect("reading storage stays heap-silent");
assert!(seen > 0, "the windowed reads really visited components");
let verdict = counters::quiet_window(5, || {
for round in 0..8u32 {
for entity in &live {
if let Some(value) = store.get_mut(entity.index()) {
*value = value.wrapping_add(round);
}
}
}
});
verdict.expect("mutating components in place stays heap-silent");
let verdict = counters::quiet_window(5, || {
for _ in 0..8 {
let doomed = live.pop().expect("the fixture is not empty");
store.remove(doomed.index());
assert!(entities.despawn(doomed));
let reborn = entities.spawn();
store.insert(reborn.index(), 7);
live.push(reborn);
}
});
verdict.expect("churn inside the high-water mark stays heap-silent");
assert_eq!(
store.len(),
SLOTS as usize,
"churn left the population where it was"
);
let mut touched = 0u32;
let verdict = counters::quiet_window(1, || {
store.for_each_mut(|_, value| {
touched += 1;
*value = value.wrapping_add(1);
});
});
assert_eq!(touched, SLOTS, "the walk really visited every component");
assert!(
verdict.is_err(),
"the ordered mutable walk no longer allocates — if that is deliberate, this \
expectation is the stale half and should become an assertion that it \
stays free rather than one that it is not"
);
}