#![cfg(all(feature = "storage", feature = "secondary-indexes"))]
use core::num::NonZeroU32;
use core::ops::Bound::{Excluded, Included, Unbounded};
use pipecircuit::storage::warp_table::{
Capacity, RangeIndexBounds, RangeIndexLookupError, RangeQueryWorkspace,
RangeWorkspaceLookupError, WarpTable, WarpTableInsertOutcome, WarpTableRemoveOutcome,
WarpTableRow,
};
#[global_allocator]
static ALLOCATOR: dhat::Alloc = dhat::Alloc;
#[derive(WarpTableRow)]
struct Row {
#[index(range)]
rank: u64,
}
#[test]
fn caller_storage_preserves_membership_across_reuse_without_allocating() -> Result<(), &'static str>
{
{
let profiler = dhat::Profiler::builder().testing().build();
let calibration = core::hint::black_box(vec![0_u64; 17]);
assert_eq!(dhat::HeapStats::get().total_blocks, 1);
assert_eq!(dhat::HeapStats::get().total_bytes, 136);
drop(calibration);
drop(profiler);
}
for capacity in [1, 63, 64, 65, 129, 1025] {
let mut table =
WarpTable::<Row>::try_new(Capacity::new(NonZeroU32::new(capacity).ok_or("capacity")?))
.map_err(|_| "table")?;
let mut first_id = None;
for rank in 0..capacity {
let WarpTableInsertOutcome::Inserted { id, .. } = table.insert(Row {
rank: u64::from(rank),
}) else {
return Err("insert");
};
first_id.get_or_insert(id);
}
assert!(matches!(
table.remove(first_id.ok_or("first")?),
WarpTableRemoveOutcome::Removed { .. }
));
assert!(matches!(
table.insert(Row { rank: 9999 }),
WarpTableInsertOutcome::Inserted { .. }
));
let required_words = table.range_query_workspace_words();
let mut storage = vec![u64::MAX; required_words.saturating_add(1)];
let mut workspace = RangeQueryWorkspace::new(&mut storage);
let queries = [
(Unbounded, Unbounded),
(Included(9999), Included(9999)),
(Included(0), Included(0)),
(Included(1), Excluded(65)),
(Excluded(63), Included(129)),
(Excluded(9999), Unbounded),
(Unbounded, Excluded(64)),
(Excluded(65), Included(65)),
];
for bounds in queries.into_iter().cycle().take(24) {
let owned = table
.query()
.find_rank_in(bounds)
.map_err(|_| "owned range")?;
let expected_count = owned.len();
let expected_sum = owned.rows().map(|row| *row.rank).sum::<u64>();
let profiler = dhat::Profiler::builder().testing().build();
let selection = table
.query()
.find_rank_in_with(bounds, &mut workspace)
.map_err(|_| "workspace range")?;
assert_eq!(selection.bounds(), &RangeIndexBounds::from_range(bounds));
assert_eq!(selection.len(), expected_count);
assert_eq!(selection.is_empty(), expected_count == 0);
let mut actual_count = 0_u64;
let actual_sum = selection
.rows()
.map(|row| {
actual_count = actual_count.saturating_add(1);
*row.rank
})
.sum::<u64>();
assert_eq!(actual_count, expected_count);
assert_eq!(actual_sum, expected_sum);
let stats = dhat::HeapStats::get();
assert_eq!((stats.total_blocks, stats.total_bytes), (0, 0));
drop(profiler);
}
let too_small = required_words.saturating_sub(1);
let mut short = vec![19; too_small];
let mut short_workspace = RangeQueryWorkspace::new(&mut short);
assert!(matches!(
table.query().find_rank_in_with(.., &mut short_workspace),
Err(RangeWorkspaceLookupError::WorkspaceTooSmall { required_words: required, available_words })
if required == required_words && available_words == too_small
));
assert!(short.iter().all(|word| *word == 19));
assert!(matches!(
table
.query()
.find_rank_in_with((Included(99), Included(1)), &mut workspace),
Err(RangeWorkspaceLookupError::Lookup {
reason: RangeIndexLookupError::ReversedBounds { .. }
})
));
assert_eq!(storage.last(), Some(&u64::MAX));
}
Ok(())
}