use super::bucket::{next_bucket, reduce};
use super::{DenseKeyIndex, EMPTY_ROW, IndexInconsistency};
use crate::storage::warp_table::IndexKey;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub(in crate::storage::warp_table) enum FindOutcome<'keys, Key> {
Present {
location: FoundLocation,
key: &'keys Key,
},
Absent,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::storage::warp_table) struct FoundLocation {
pub(in crate::storage::warp_table::dense_key_index) bucket: usize,
pub(in crate::storage::warp_table::dense_key_index) stored_row: u32,
pub(in crate::storage::warp_table) row: usize,
}
impl DenseKeyIndex {
pub(in crate::storage::warp_table) fn find<'keys, Key: IndexKey>(
&self,
key: Key,
keys: &'keys [Key],
) -> Result<FindOutcome<'keys, Key>, IndexInconsistency> {
let mut bucket = reduce(key.index_word(), self.buckets.len());
for _ in 0..self.buckets.len() {
let stored_row = self
.buckets
.get(bucket)
.copied()
.ok_or(IndexInconsistency::BucketUnavailable { bucket })?;
if stored_row == EMPTY_ROW {
return Ok(FindOutcome::Absent);
}
let row = represent_stored_row(stored_row)?;
let Some(stored_key) = keys.get(row) else {
return Err(IndexInconsistency::KeyUnavailable { row });
};
if *stored_key == key {
return Ok(FindOutcome::Present {
location: FoundLocation {
bucket,
stored_row,
row,
},
key: stored_key,
});
}
bucket = next_bucket(bucket, self.buckets.len());
}
Err(IndexInconsistency::ProbeLimitReached)
}
}
pub(super) fn represent_stored_row<Index: TryFrom<u32>>(
stored_row: u32,
) -> Result<Index, IndexInconsistency> {
Index::try_from(stored_row)
.map_err(|_| IndexInconsistency::StoredRowUnrepresentable { stored_row })
}