use super::rows::resolve;
use crate::storage::warp_table::secondary_index::{
RangeWorkspaceMembership, StableSlot, StableSlotResolver,
};
use crate::storage::warp_table::{RangeIndexBounds, WarpTable, WarpTableRow};
#[must_use]
pub struct RangeSelection<'table, 'workspace, Row: WarpTableRow, Brand, Key> {
table: &'table WarpTable<Row, Brand>,
bounds: RangeIndexBounds<Key>,
words: &'workspace [u64],
len: u64,
}
impl<'table, 'workspace, Row: WarpTableRow, Brand, Key>
RangeSelection<'table, 'workspace, Row, Brand, Key>
{
pub fn bounds(&self) -> &RangeIndexBounds<Key> {
&self.bounds
}
pub fn len(&self) -> u64 {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn rows(self) -> impl Iterator<Item = Row::Ref<'table>> + 'workspace
where
'table: 'workspace,
Row::Indexes: StableSlotResolver,
{
(0..=u32::MAX)
.step_by(u64::BITS as usize)
.zip(self.words)
.flat_map(|(base, word)| word_slots(base, *word))
.map(move |slot| resolve(self.table, slot))
}
}
#[allow(
clippy::arithmetic_side_effects,
reason = "bases are multiples of 64 within u32; each bit is below 64 and subtraction follows a nonzero check"
)]
fn word_slots(base: u32, mut word: u64) -> impl Iterator<Item = StableSlot> {
core::iter::from_fn(move || {
if word == 0 {
return None;
}
let bit = word.trailing_zeros();
word &= word - 1;
Some(StableSlot::new(base + bit))
})
}
#[doc(hidden)]
pub fn bind_range_workspace_lookup<'table, 'workspace, Row: WarpTableRow, Brand, Key>(
table: &'table WarpTable<Row, Brand>,
membership: RangeWorkspaceMembership<'workspace, Key>,
) -> RangeSelection<'table, 'workspace, Row, Brand, Key> {
let (bounds, words, len) = membership.into_parts();
RangeSelection {
table,
bounds,
words,
len,
}
}