extern crate alloc;
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::num::{NonZeroU32, NonZeroU64};
use super::placement::{Anchor, Dot, Locus};
use super::wire::{apply_chain_step, chain_step};
use crate::metis::dot::RawDot;
pub(super) const PAGE_LEN: usize = 64;
const PAGE_LEN_U64: u64 = 64;
const LIVE_CAP: usize = Slot::PAYLOAD_MAX as usize - 1;
pub(in crate::metis::rhapsody) const PLANE_CAPACITY: usize = LIVE_CAP;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct RawHandle(NonZeroU32);
impl RawHandle {
fn from_index(index: usize) -> Option<Self> {
u32::try_from(index)
.ok()
.and_then(|raw| raw.checked_add(1))
.filter(|&raw| raw <= Slot::PAYLOAD_MAX)
.and_then(NonZeroU32::new)
.map(Self)
}
const fn index(self) -> usize {
self.0.get() as usize - 1
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Slot(u32);
const _: () = assert!(core::mem::size_of::<Slot>() == 4);
const _: () = assert!(core::mem::size_of::<Option<RawHandle>>() == 4);
impl Slot {
const EMPTY: Self = Self(0);
const STEP_BIT: u32 = 0x8000_0000;
const PAYLOAD_MAX: u32 = 0x7FFF_FFFF;
const fn is_empty(self) -> bool {
self.0 == 0
}
const fn explicit(handle: RawHandle) -> Self {
Self(handle.0.get())
}
fn step(step: u64) -> Option<Self> {
u32::try_from(step)
.ok()
.filter(|&raw| raw <= Self::PAYLOAD_MAX)
.map(|raw| Self(Self::STEP_BIT | raw))
}
fn as_explicit(self) -> Option<RawHandle> {
if self.0 & Self::STEP_BIT == 0 {
NonZeroU32::new(self.0).map(RawHandle)
} else {
None
}
}
const fn as_step(self) -> Option<u64> {
if self.0 & Self::STEP_BIT == 0 {
None
} else {
Some((self.0 & Self::PAYLOAD_MAX) as u64)
}
}
}
#[derive(Clone, Debug)]
struct Page {
slots: [Slot; PAGE_LEN],
occupancy: u16,
}
impl Page {
const fn empty() -> Self {
Self {
slots: [Slot::EMPTY; PAGE_LEN],
occupancy: 0,
}
}
}
#[derive(Clone, Debug, Default)]
struct StationFiber {
prefix: Vec<Option<Box<Page>>>,
above: BTreeMap<u64, Box<Page>>,
}
impl StationFiber {
fn is_empty(&self) -> bool {
self.above.is_empty() && self.prefix.iter().all(Option::is_none)
}
fn page(&self, page_number: u64) -> Option<&Page> {
match usize::try_from(page_number) {
Ok(offset) if offset < self.prefix.len() => self.prefix[offset].as_deref(),
_ => self.above.get(&page_number).map(Box::as_ref),
}
}
fn page_mut(&mut self, page_number: u64) -> Option<&mut Page> {
match usize::try_from(page_number) {
Ok(offset) if offset < self.prefix.len() => self.prefix[offset].as_deref_mut(),
_ => self.above.get_mut(&page_number).map(Box::as_mut),
}
}
fn page_mut_or_create(&mut self, page_number: u64) -> &mut Page {
if let Ok(offset) = usize::try_from(page_number) {
if offset < self.prefix.len() {
return self.prefix[offset].get_or_insert_with(|| Box::new(Page::empty()));
}
if offset == self.prefix.len() {
self.prefix.push(Some(Box::new(Page::empty())));
self.promote_contiguous_exceptions();
return self.prefix[offset]
.as_deref_mut()
.expect("the page was just pushed");
}
}
self.above
.entry(page_number)
.or_insert_with(|| Box::new(Page::empty()))
}
fn promote_contiguous_exceptions(&mut self) {
while let Ok(next) = u64::try_from(self.prefix.len()) {
let Some(page) = self.above.remove(&next) else {
break;
};
self.prefix.push(Some(page));
}
}
fn free_page(&mut self, page_number: u64) {
match usize::try_from(page_number) {
Ok(offset) if offset < self.prefix.len() => {
self.prefix[offset] = None;
while self.prefix.last().is_some_and(Option::is_none) {
let _ = self.prefix.pop();
}
}
_ => {
let _ = self.above.remove(&page_number);
}
}
}
}
fn page_slot(index: u64) -> (u64, usize) {
(
(index - 1) / PAGE_LEN_U64,
usize::from(
u8::try_from((index - 1) % PAGE_LEN_U64).expect("page slot modulo PAGE_LEN fits in u8"),
),
)
}
#[derive(Clone, Debug, Default)]
pub(super) struct IdentityPlane {
stations: BTreeMap<u32, StationFiber>,
loci: Vec<Locus>,
free: Vec<RawHandle>,
len: usize,
}
impl IdentityPlane {
pub(super) const fn new() -> Self {
Self {
stations: BTreeMap::new(),
loci: Vec::new(),
free: Vec::new(),
len: 0,
}
}
pub(super) const fn len(&self) -> usize {
self.len
}
pub(super) const fn is_empty(&self) -> bool {
self.len == 0
}
pub(super) const fn has_capacity_for(&self, additional: usize) -> bool {
self.len.saturating_add(additional) <= LIVE_CAP
}
pub(super) fn contains(&self, dot: Dot) -> bool {
let (station, index) = (dot.station(), dot.counter());
let (page_number, slot) = page_slot(index);
self.stations
.get(&station)
.and_then(|fiber| fiber.page(page_number))
.is_some_and(|page| !page.slots[slot].is_empty())
}
fn materialize(&self, station: u32, page_number: u64, page: &Page, slot: usize) -> Locus {
let mut explicit = slot;
let handle = loop {
if let Some(handle) = page.slots[explicit].as_explicit() {
break handle;
}
debug_assert!(explicit > 0, "slot zero of a page is always explicit");
explicit -= 1;
};
let mut locus = self.loci[handle.index()];
for k in (explicit + 1)..=slot {
let step = page.slots[k]
.as_step()
.expect("the walk back stopped at the nearest explicit slot");
let prev_dot = (station, page_number * PAGE_LEN_U64 + k as u64);
locus = apply_chain_step(prev_dot, &locus, step);
}
locus
}
pub(super) fn anchor_of(&self, dot: &Dot) -> Option<Anchor> {
let (station, index) = (dot.station(), dot.counter());
let (page_number, slot) = page_slot(index);
let page = self.stations.get(&station)?.page(page_number)?;
let entry = page.slots[slot];
if let Some(handle) = entry.as_explicit() {
return Some(self.loci[handle.index()].anchor);
}
if entry.as_step().is_some() {
return Some(Anchor::After(RawDot {
station,
counter: index - 1,
}));
}
None
}
pub(super) fn get(&self, dot: &Dot) -> Option<Locus> {
let (station, index) = (dot.station(), dot.counter());
let (page_number, slot) = page_slot(index);
let page = self.stations.get(&station)?.page(page_number)?;
if page.slots[slot].is_empty() {
return None;
}
Some(self.materialize(station, page_number, page, slot))
}
fn intern(&mut self, locus: Locus) -> RawHandle {
if let Some(handle) = self.free.pop() {
self.loci[handle.index()] = locus;
handle
} else {
let handle = RawHandle::from_index(self.loci.len())
.expect("the live-entry cap reserves column capacity for every explicit slot");
self.loci.push(locus);
handle
}
}
pub(super) fn insert(&mut self, dot: Dot, locus: Locus) -> bool {
self.insert_inner(dot, locus, None)
}
pub(super) fn extend_ascending(&mut self, entries: impl IntoIterator<Item = (Dot, Locus)>) {
let mut prev: Option<(Dot, Locus)> = None;
for (dot, locus) in entries {
let hint = match &prev {
Some((prev_dot, prev_locus))
if prev_dot.station() == dot.station()
&& prev_dot.counter().checked_add(1) == Some(dot.counter()) =>
{
Some(prev_locus)
}
_ => None,
};
prev = if self.insert_inner(dot, locus, hint) {
Some((dot, locus))
} else {
None
};
}
}
fn insert_inner(&mut self, dot: Dot, locus: Locus, prev_hint: Option<&Locus>) -> bool {
let (station, index) = (dot.station(), dot.counter());
if self.len >= LIVE_CAP {
return false;
}
let (page_number, slot) = page_slot(index);
let mut inline: Option<Slot> = None;
if let Some(page) = self
.stations
.get(&station)
.and_then(|fiber| fiber.page(page_number))
{
if !page.slots[slot].is_empty() {
return false;
}
if slot > 0 && !page.slots[slot - 1].is_empty() {
let prev_dot = (station, index - 1);
let step = prev_hint.map_or_else(
|| {
let prev = self.materialize(station, page_number, page, slot - 1);
chain_step(prev_dot, &prev, (station, index), &locus)
},
|prev| chain_step(prev_dot, prev, (station, index), &locus),
);
inline = step.and_then(Slot::step);
}
}
let entry = inline.unwrap_or_else(|| Slot::explicit(self.intern(locus)));
let page = self
.stations
.entry(station)
.or_default()
.page_mut_or_create(page_number);
page.slots[slot] = entry;
page.occupancy += 1;
self.len += 1;
true
}
pub(super) fn insert_run(&mut self, first_dot: Dot, loci: &[Locus]) -> bool {
let (station, first) = (first_dot.station(), first_dot.counter());
let len = loci.len();
if len == 0 {
return false;
}
let Some(last) = first.checked_add(len as u64 - 1) else {
return false;
};
if !self.has_capacity_for(len) {
return false;
}
if let Some(fiber) = self.stations.get(&station) {
let (first_page, _) = page_slot(first);
let (last_page, _) = page_slot(last);
for page_number in first_page..=last_page {
let Some(page) = fiber.page(page_number) else {
continue;
};
let from = if page_number == first_page {
page_slot(first).1
} else {
0
};
let to = if page_number == last_page {
page_slot(last).1
} else {
PAGE_LEN - 1
};
if page.slots[from..=to].iter().any(|slot| !slot.is_empty()) {
return false;
}
}
}
if !self.insert_inner(first_dot, loci[0], None) {
debug_assert!(false, "the freshness sweep admitted the head");
return false;
}
let mut prev = loci[0];
let mut at = 1usize;
while at < len {
let index = first + at as u64;
let (page_number, slot_from) = page_slot(index);
let take = (PAGE_LEN - slot_from).min(len - at);
let mut entries: [Slot; PAGE_LEN] = [Slot::EMPTY; PAGE_LEN];
for (k, entry) in entries.iter_mut().enumerate().take(take) {
let locus = loci[at + k];
let prev_dot = (station, index + k as u64 - 1);
let inline = if slot_from + k > 0 {
chain_step(prev_dot, &prev, (station, index + k as u64), &locus)
.and_then(Slot::step)
} else {
None
};
*entry = inline.unwrap_or_else(|| Slot::explicit(self.intern(locus)));
prev = locus;
}
let page = self
.stations
.entry(station)
.or_default()
.page_mut_or_create(page_number);
for (slot, &entry) in page.slots[slot_from..slot_from + take]
.iter_mut()
.zip(&entries)
{
debug_assert!(slot.is_empty(), "the sweep verified");
*slot = entry;
}
page.occupancy += u16::try_from(take).expect("a page holds at most PAGE_LEN slots");
self.len += take;
at += take;
}
true
}
pub(super) fn remove(&mut self, dot: Dot) -> Option<Locus> {
let (station, index) = (dot.station(), dot.counter());
let (page_number, slot) = page_slot(index);
let page = self.stations.get(&station)?.page(page_number)?;
if page.slots[slot].is_empty() {
return None;
}
let locus = self.materialize(station, page_number, page, slot);
let follower = (slot + 1 < PAGE_LEN && page.slots[slot + 1].as_step().is_some())
.then(|| self.materialize(station, page_number, page, slot + 1));
let follower_entry =
follower.map(|follower_locus| Slot::explicit(self.intern(follower_locus)));
let fiber = self
.stations
.get_mut(&station)
.expect("the fiber was probed above");
let page = fiber
.page_mut(page_number)
.expect("the page was probed above");
if let Some(entry) = follower_entry {
page.slots[slot + 1] = entry;
}
let departing = page.slots[slot];
page.slots[slot] = Slot::EMPTY;
page.occupancy -= 1;
let emptied = page.occupancy == 0;
if let Some(handle) = departing.as_explicit() {
self.free.push(handle);
}
if emptied {
fiber.free_page(page_number);
}
if fiber.is_empty() {
let _ = self.stations.remove(&station);
}
self.len -= 1;
Some(locus)
}
pub(super) fn iter(&self) -> impl Iterator<Item = (Dot, Locus)> + '_ {
self.stations.iter().flat_map(move |(&station, fiber)| {
let prefix = fiber
.prefix
.iter()
.enumerate()
.filter_map(|(number, page)| page.as_deref().map(|page| (number as u64, page)));
let above = fiber
.above
.iter()
.map(|(&number, page)| (number, page.as_ref()));
prefix.chain(above).flat_map(move |(number, page)| {
let mut last: Option<Locus> = None;
page.slots
.iter()
.enumerate()
.filter_map(move |(slot, entry)| {
if entry.is_empty() {
last = None;
return None;
}
let index = number * PAGE_LEN as u64 + slot as u64 + 1;
let locus = entry.as_explicit().map_or_else(
|| {
let step = entry
.as_step()
.expect("an occupied slot is explicit or stepped");
let prev =
last.expect("a stepped slot's predecessor is always occupied");
apply_chain_step((station, index - 1), &prev, step)
},
|handle| self.loci[handle.index()],
);
last = Some(locus);
let counter = NonZeroU64::new(index)
.expect("a page slot's one-based index is at least one");
Some((Dot::new(station, counter), locus))
})
})
})
}
#[cfg(test)]
fn pages_allocated(&self) -> usize {
self.stations
.values()
.map(|fiber| {
fiber.prefix.iter().filter(|page| page.is_some()).count() + fiber.above.len()
})
.sum()
}
#[cfg(test)]
const fn column_len(&self) -> usize {
self.loci.len()
}
#[cfg(any(test, feature = "instrumentation"))]
pub(super) const fn explicit_entries(&self) -> usize {
self.loci.len() - self.free.len()
}
}
impl PartialEq for IdentityPlane {
fn eq(&self, other: &Self) -> bool {
self.len == other.len && self.iter().eq(other.iter())
}
}
impl Eq for IdentityPlane {}
impl core::hash::Hash for IdentityPlane {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write_usize(self.len);
for entry in self.iter() {
entry.hash(state);
}
}
}
#[cfg(test)]
mod tests;