use crate::{db::executor::projection::ProjectionValidationRow, value::Value};
use std::sync::Arc;
#[derive(Clone, Debug)]
pub(in crate::db::executor) struct RetainedSlotLayout {
data: Arc<RetainedSlotLayoutData>,
}
#[derive(Debug)]
struct RetainedSlotLayoutData {
required_slots: Box<[usize]>,
slot_to_value_index: Box<[Option<usize>]>,
}
impl RetainedSlotLayout {
#[must_use]
pub(in crate::db::executor) fn compile(slot_count: usize, required_slots: Vec<usize>) -> Self {
let mut slot_to_value_index = vec![None; slot_count];
for (value_index, &slot) in required_slots.iter().enumerate() {
if let Some(entry) = slot_to_value_index.get_mut(slot) {
*entry = Some(value_index);
}
}
Self {
data: Arc::new(RetainedSlotLayoutData {
required_slots: required_slots.into_boxed_slice(),
slot_to_value_index: slot_to_value_index.into_boxed_slice(),
}),
}
}
#[must_use]
pub(in crate::db::executor) fn required_slots(&self) -> &[usize] {
self.data.required_slots.as_ref()
}
#[must_use]
pub(in crate::db::executor) fn value_index_for_slot(&self, slot: usize) -> Option<usize> {
self.data.slot_to_value_index.get(slot).copied().flatten()
}
#[must_use]
pub(in crate::db::executor) fn slot_count(&self) -> usize {
self.data.slot_to_value_index.len()
}
#[must_use]
pub(in crate::db::executor) fn retained_value_count(&self) -> usize {
self.data.required_slots.len()
}
}
pub(in crate::db) struct RetainedSlotRow {
storage: RetainedSlotRowStorage,
}
struct RetainedSlotEntry {
slot: usize,
value: Option<Value>,
}
enum RetainedSlotRowStorage {
Indexed {
layout: RetainedSlotLayout,
values: Vec<Option<Value>>,
},
Sparse {
slot_count: usize,
entries: Vec<RetainedSlotEntry>,
},
}
impl RetainedSlotRow {
#[cfg(test)]
#[must_use]
pub(in crate::db) fn new(slot_count: usize, entries: Vec<(usize, Value)>) -> Self {
let mut compact_entries = entries
.into_iter()
.filter(|(slot, _)| *slot < slot_count)
.collect::<Vec<_>>();
compact_entries.sort_by_key(|(slot, _)| *slot);
let mut deduped_entries: Vec<RetainedSlotEntry> = Vec::with_capacity(compact_entries.len());
for (slot, value) in compact_entries {
if let Some(entry) = deduped_entries.last_mut()
&& entry.slot == slot
{
entry.value = Some(value);
} else {
deduped_entries.push(RetainedSlotEntry {
slot,
value: Some(value),
});
}
}
Self {
storage: RetainedSlotRowStorage::Sparse {
slot_count,
entries: deduped_entries,
},
}
}
#[must_use]
pub(in crate::db::executor) fn from_dense_slots(slots: Vec<Option<Value>>) -> Self {
let slot_count = slots.len();
let mut entries = Vec::new();
for (slot, value) in slots.into_iter().enumerate() {
let Some(value) = value else {
continue;
};
entries.push(RetainedSlotEntry {
slot,
value: Some(value),
});
}
Self {
storage: RetainedSlotRowStorage::Sparse {
slot_count,
entries,
},
}
}
#[must_use]
pub(in crate::db::executor) fn from_indexed_values(
layout: &RetainedSlotLayout,
values: Vec<Option<Value>>,
) -> Self {
debug_assert_eq!(values.len(), layout.retained_value_count());
Self {
storage: RetainedSlotRowStorage::Indexed {
layout: layout.clone(),
values,
},
}
}
#[must_use]
pub(in crate::db) fn slot_ref(&self, slot: usize) -> Option<&Value> {
match &self.storage {
RetainedSlotRowStorage::Indexed { layout, values } => {
let index = layout.value_index_for_slot(slot)?;
values.get(index).and_then(Option::as_ref)
}
RetainedSlotRowStorage::Sparse { entries, .. } => {
Self::find_sparse_entry(entries.as_slice(), slot)
.and_then(|entry| entry.value.as_ref())
}
}
}
pub(in crate::db) fn take_slot(&mut self, slot: usize) -> Option<Value> {
match &mut self.storage {
RetainedSlotRowStorage::Indexed { layout, values } => {
let index = layout.value_index_for_slot(slot)?;
values.get_mut(index)?.take()
}
RetainedSlotRowStorage::Sparse { entries, .. } => {
let index = Self::find_sparse_entry_index(entries.as_slice(), slot)?;
entries.get_mut(index)?.value.take()
}
}
}
#[must_use]
pub(in crate::db::executor) fn into_dense_slots(self) -> Vec<Option<Value>> {
match self.storage {
RetainedSlotRowStorage::Indexed { layout, values } => {
let mut slots = vec![None; layout.slot_count()];
for (&slot, value) in layout.required_slots().iter().zip(values) {
slots[slot] = value;
}
slots
}
RetainedSlotRowStorage::Sparse {
slot_count,
entries,
} => {
let mut slots = vec![None; slot_count];
for entry in entries {
if let Some(value) = entry.value {
slots[entry.slot] = Some(value);
}
}
slots
}
}
}
fn find_sparse_entry(entries: &[RetainedSlotEntry], slot: usize) -> Option<&RetainedSlotEntry> {
let index = Self::find_sparse_entry_index(entries, slot)?;
entries.get(index)
}
fn find_sparse_entry_index(entries: &[RetainedSlotEntry], slot: usize) -> Option<usize> {
entries.binary_search_by_key(&slot, |entry| entry.slot).ok()
}
}
impl ProjectionValidationRow for RetainedSlotRow {
fn projection_validation_slot_value(&self, slot: usize) -> Option<&Value> {
self.slot_ref(slot)
}
}