use super::{
SlotSet,
membership::{Chunk, Membership},
};
use crate::storage::{
membership::{BucketMembership, MembershipChunks},
query_workspace::chunk::read::ChunkRead,
};
use core::slice;
#[derive(Clone, Copy)]
pub(in crate::storage::warp_table) enum SlotSetRead<'a> {
Empty,
Owned(&'a SlotSet),
Indexed(BucketMembership<'a>),
}
#[allow(
clippy::large_enum_variant,
reason = "borrowed index traversal retains its bounded stacks without allocation"
)]
pub(in crate::storage::warp_table) enum Chunks<'a> {
Empty,
Owned(slice::Iter<'a, Chunk>),
Indexed(MembershipChunks<'a>),
}
impl<'a> Iterator for Chunks<'a> {
type Item = (u16, ChunkRead<'a>);
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Empty => None,
Self::Owned(chunks) => chunks.next().map(|chunk| (chunk.high, chunk.read())),
Self::Indexed(chunks) => chunks.next().map(|(high, chunk)| (high, chunk.0)),
}
}
}
impl DoubleEndedIterator for Chunks<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
Self::Empty => None,
Self::Owned(chunks) => chunks.next_back().map(|chunk| (chunk.high, chunk.read())),
Self::Indexed(chunks) => chunks.next_back().map(|(high, chunk)| (high, chunk.0)),
}
}
}
impl<'a> SlotSetRead<'a> {
pub(in crate::storage::warp_table) fn chunks(self) -> Chunks<'a> {
match self {
Self::Empty => Chunks::Empty,
Self::Owned(set) => Chunks::Owned(set.0.chunks.iter()),
Self::Indexed(members) => Chunks::Indexed(members.chunks()),
}
}
pub(in crate::storage::warp_table) fn len(self) -> u64 {
match self {
Self::Empty => 0,
Self::Owned(set) => set.len(),
Self::Indexed(members) => members.len() as u64,
}
}
pub(in crate::storage::warp_table) fn slots(self) -> super::SlotSetSlots<'a> {
super::lookup::read_slots(self)
}
pub(in crate::storage::warp_table) fn is_subset(self, other: Self) -> bool {
if self.len() > other.len() {
return false;
}
let mut right = other.chunks().peekable();
self.chunks().all(|(high, left)| {
while right.peek().is_some_and(|(key, _)| *key < high) {
right.next();
}
let other = right
.next_if(|(key, _)| *key == high)
.map_or(ChunkRead::EMPTY, |(_, chunk)| chunk);
left.is_subset(other)
})
}
pub(in crate::storage::warp_table) fn is_disjoint(self, other: Self) -> bool {
let mut right = other.chunks().peekable();
self.chunks().all(|(high, left)| {
while right.peek().is_some_and(|(key, _)| *key < high) {
right.next();
}
let other = right
.next_if(|(key, _)| *key == high)
.map_or(ChunkRead::EMPTY, |(_, chunk)| chunk);
left.is_disjoint(other)
})
}
}
impl SlotSet {
pub(in crate::storage::warp_table) const fn read(&self) -> SlotSetRead<'_> {
SlotSetRead::Owned(self)
}
pub(in crate::storage::warp_table) fn from_read(source: SlotSetRead<'_>) -> Self {
Self(Membership {
len: source.len(),
chunks: source
.chunks()
.map(|(high, read)| Chunk::from_read(high, read))
.collect(),
})
}
}