#![cfg(all(feature = "storage", feature = "secondary-indexes"))]
use core::num::NonZeroU32;
use core::ops::Bound::{Included, Unbounded};
use pipecircuit::storage::warp_table::{
Capacity, Selection, WarpTable, WarpTableInsertOutcome, WarpTableRow,
};
#[global_allocator]
static ALLOCATOR: dhat::Alloc = dhat::Alloc;
#[derive(WarpTableRow)]
struct Row {
#[index(range)]
rank: u64,
#[index(secondary)]
group: u8,
}
#[test]
fn range_query_allocations_match_block_and_reuse_bounds() -> Result<(), &'static str> {
let mut first_bytes = None;
for (capacity, additional_bytes) in [(1, 0), (64, 0), (65, 24), (129, 48)] {
let mut table =
WarpTable::<Row>::try_new(Capacity::new(NonZeroU32::new(capacity).ok_or("capacity")?))
.map_err(|_| "table")?;
for rank in 0..capacity {
assert!(matches!(
table.insert(Row {
rank: u64::from(rank),
group: 0,
}),
WarpTableInsertOutcome::Inserted { .. }
));
}
let _profiler = dhat::Profiler::builder().testing().build();
for bounds in [
(Included(999), Included(999)),
(Included(999), Included(1000)),
(Included(999), Unbounded),
] {
let selection = table.query().find_rank_in(bounds).map_err(|_| "range")?;
assert!(selection.is_empty());
assert_eq!(selection.len(), 0);
}
let stats = dhat::HeapStats::get();
assert_eq!(stats.total_blocks, 6);
let baseline = first_bytes.get_or_insert(stats.total_bytes);
assert_eq!(
stats.total_bytes.checked_sub(*baseline),
Some(additional_bytes)
);
assert_eq!(stats.curr_blocks, 0);
}
let mut table =
WarpTable::<Row>::try_new(Capacity::new(NonZeroU32::new(129).ok_or("capacity")?))
.map_err(|_| "table")?;
for rank in 0..129 {
assert!(matches!(
table.insert(Row { rank, group: 0 }),
WarpTableInsertOutcome::Inserted { .. }
));
}
for (owned, reverse) in [(false, false), (false, true), (true, false), (true, true)] {
let _profiler = dhat::Profiler::builder().testing().build();
let smaller = table.query().find_rank_in(7..=7).map_err(|_| "smaller")?;
let larger: Selection<'_, Row> = if owned {
table.query().find_rank_in(..).map_err(|_| "larger")?.into()
} else {
table.query().find_group(0).into()
};
let before = dhat::HeapStats::get();
let selected = if reverse {
larger.and_selection(smaller)
} else {
smaller.and_selection(larger)
};
assert_eq!(selected.len(), 1);
let after = dhat::HeapStats::get();
assert_eq!(after.total_blocks, before.total_blocks);
assert_eq!(after.total_bytes, before.total_bytes);
assert_eq!(*selected.rows().next().ok_or("selected row")?.rank, 7);
assert_eq!(dhat::HeapStats::get().curr_blocks, 0);
}
Ok(())
}