use super::bucket::{next_bucket, reduce};
use super::{
DenseKeyIndex, EMPTY_ROW, FindOutcome, IndexInconsistency, PrepareRemoveOutcome,
PreparedRemoval,
};
use crate::storage::warp_table::IndexKey;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::storage::warp_table) struct PreparedReplacement<Key> {
removal: PreparedRemoval<Key>,
replacement: Key,
stored_row: u32,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub(in crate::storage::warp_table) enum PrepareReplaceOutcome<Key> {
Prepared(PreparedReplacement<Key>),
Unchanged { row: usize },
OriginalAbsent,
ReplacementPresent { row: usize },
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub(in crate::storage::warp_table) enum ReplaceOutcome {
Replaced { row: usize },
}
impl DenseKeyIndex {
pub(in crate::storage::warp_table) fn prepare_replace<Key: IndexKey>(
&self,
original: Key,
replacement: Key,
keys: &[Key],
) -> Result<PrepareReplaceOutcome<Key>, IndexInconsistency> {
let (row, stored_row) = match self.find(original, keys)? {
FindOutcome::Present {
row, stored_row, ..
} => (row, stored_row),
FindOutcome::Absent => return Ok(PrepareReplaceOutcome::OriginalAbsent),
};
if original == replacement {
return Ok(PrepareReplaceOutcome::Unchanged { row });
}
if let FindOutcome::Present { row, .. } = self.find(replacement, keys)? {
return Ok(PrepareReplaceOutcome::ReplacementPresent { row });
}
let removal = match self.prepare_remove(original, keys, row)? {
PrepareRemoveOutcome::Prepared(removal) => removal,
PrepareRemoveOutcome::Absent => return Ok(PrepareReplaceOutcome::OriginalAbsent),
};
Ok(PrepareReplaceOutcome::Prepared(PreparedReplacement {
removal,
replacement,
stored_row,
}))
}
#[allow(
clippy::indexing_slicing,
reason = "replacement preparation proves a removable entry and a spare bucket"
)]
pub(in crate::storage::warp_table) fn commit_replace<Key: IndexKey>(
&mut self,
replacement: PreparedReplacement<Key>,
keys: &[Key],
) -> ReplaceOutcome {
let row = replacement.removal.row;
self.commit_remove(replacement.removal, keys);
let mut bucket = reduce(replacement.replacement.index_word(), self.buckets.len());
loop {
if self.buckets[bucket] == EMPTY_ROW {
self.buckets[bucket] = replacement.stored_row;
return ReplaceOutcome::Replaced { row };
}
bucket = next_bucket(bucket, self.buckets.len());
}
}
}