use std::{array, iter, mem, num::NonZero};
pub use entry::Entry;
pub use error::Error;
use crate::{
alloc::{self, BoxSliceExt as _, VecExt as _, raw::VecExt as _},
base::marker::ThreadBound,
depot::{
capacity,
heap::indexed,
queue::{
indexed::{lanes::runtime, planes},
links,
},
},
};
pub mod bound;
mod entry;
pub mod groups;
pub mod resident;
pub use state::State;
mod error;
pub mod map;
pub mod phase;
pub trait Seed<T> {
fn seed(&self, index: links::Index) -> T;
}
impl<T: Default> Seed<T> for () {
fn seed(&self, _: links::Index) -> T {
T::default()
}
}
mod state;
#[repr(C)]
struct Node<T, const PLANES: usize> {
value: T,
hooks: [links::Hook; PLANES],
}
impl<T, const PLANES: usize> Node<T, PLANES> {
fn new(index: links::Index, value: T) -> Self {
Self {
value,
hooks: array::from_fn(|_| links::Hook::new(index)),
}
}
}
struct Hooks<'a, T, const PLANES: usize, const PLANE: usize>(&'a [Node<T, PLANES>]);
unsafe impl<T, const PLANES: usize, const PLANE: usize> crate::depot::raw::Hooks
for Hooks<'_, T, PLANES, PLANE>
{
unsafe fn hook_raw(&self, index: links::Index) -> &'_ links::Hook {
const { assert!(PLANE < PLANES, "plane") };
let entry = unsafe { self.0.get_unchecked(index.get()) };
&entry.hooks[PLANE]
}
}
pub struct Set<T, const PLANES: usize, A = ()> {
core: Core<T, PLANES>,
index: A,
}
struct Core<T, const PLANES: usize> {
entries: Vec<Node<T, PLANES>>,
queues: [links::Chain<u32>; PLANES],
_thread: ThreadBound,
}
impl<T, const PLANES: usize> Set<T, PLANES> {
pub const ENTRY_BYTES: usize = mem::size_of::<Node<T, PLANES>>();
pub fn try_seed<S: planes::Seed<T>>(len: usize, seed: S) -> Result<Self, alloc::Error> {
let count = capacity::Count::try_count(len, alloc::Error::Overflow)?;
let len = count.get();
let entries = Box::try_from_fn(len, |index| {
let index = unsafe { links::Index::new_usize(index) };
Node::new(index, seed.seed(index))
})?
.into_vec();
Ok(Self {
core: Core {
entries,
queues: [const { links::Chain::new() }; PLANES],
_thread: ThreadBound::NEW,
},
index: (),
})
}
}
impl<T, const PLANES: usize, A> Set<T, PLANES, A> {
pub fn entry(&mut self, index: usize) -> Option<Entry<'_, T, PLANES>> {
if index >= self.len() {
return None;
}
let index = unsafe { links::Index::new_usize(index) };
Some(Entry::new(&mut self.core, index))
}
pub fn iter<const PLANE: usize>(&self) -> impl Iterator<Item = (usize, &T)> + '_ {
self.core
.iter::<PLANE>()
.map(|(index, value)| (index.get(), value))
}
pub fn front_entry<const PLANE: usize>(
&mut self,
) -> Option<Entry<'_, T, PLANES, phase::Front<PLANE>>> {
self.core.front_entry::<PLANE>()
}
pub fn len_in<const PLANE: usize>(&self) -> usize {
const { assert!(PLANE < PLANES) };
self.core.queues[PLANE].len()
}
pub fn clear<const PLANE: usize>(&mut self) {
self.core.clear::<PLANE>();
}
}
impl<T, const PLANES: usize, A> Set<T, PLANES, A> {
pub fn resolve(&self, index: usize) -> Option<(NonZero<u32>, &T)> {
self.core
.resolve(index)
.map(|(index, value)| (index.position(), value))
}
pub fn get(&self, index: usize) -> Option<&T> {
self.core.entries.get(index).map(|node| &node.value)
}
pub fn iter_mut(&mut self) -> impl ExactSizeIterator<Item = &mut T> + DoubleEndedIterator {
self.core.entries.iter_mut().map(|node| &mut node.value)
}
pub fn len(&self) -> usize {
self.core.entries.len()
}
pub fn is_empty(&self) -> bool {
self.core.entries.is_empty()
}
}
const _: () = {
assert!(mem::size_of::<Entry<'static, (), 1>>() == 2 * mem::size_of::<usize>());
assert!(
mem::size_of::<Entry<'static, (), 1, phase::Front<0>>>() == 2 * mem::size_of::<usize>()
);
};
impl<T, const PLANES: usize> Core<T, PLANES> {
fn resolve(&self, index: usize) -> Option<(links::Index, &T)> {
let entry = self.entries.get(index)?;
let index = unsafe { links::Index::new_usize(index) };
Some((index, &entry.value))
}
fn iter<const PLANE: usize>(&self) -> impl Iterator<Item = (links::Index, &T)> + '_ {
const { assert!(PLANE < PLANES) };
let mut next = self.queues[PLANE].first();
iter::from_fn(move || {
let index = next?;
let entry = unsafe { self.entries.get_unchecked(index.get()) };
next = entry.hooks[PLANE].next_index();
Some((index, &entry.value))
})
}
fn front_entry<const PLANE: usize>(
&mut self,
) -> Option<Entry<'_, T, PLANES, phase::Front<PLANE>>> {
const { assert!(PLANE < PLANES) };
let index = self.queues[PLANE].first()?;
Some(Entry::new(self, index))
}
fn clear<const PLANE: usize>(&mut self) {
while let Some(front) = self.front_entry::<PLANE>() {
front.pop();
}
}
fn first<'a, P: Ord, C: alloc::raw::Extent>(
&'a mut self,
heap: &'a mut indexed::Min<P, C>,
) -> Option<(indexed::Occupied<'a, P, C>, Entry<'a, T, PLANES>)> {
let timer = heap.first_entry()?;
let index = unsafe { links::Index::new_usize(timer.index()) };
Some((timer, Entry::new(self, index)))
}
fn select<'a, P: Ord, C: alloc::raw::Extent>(
&'a mut self,
heap: &'a mut indexed::Min<P, C>,
index: links::Index,
) -> (indexed::Entry<'a, P, C>, Entry<'a, T, PLANES>) {
let entry = Entry::new(self, index);
let live = unsafe { crate::depot::raw::Proof::new(((heap, entry), index.position())) };
indexed::Slot::<_, _, _>::from_source(live).entry()
}
fn grow_with<P: Ord, C: alloc::raw::Extent>(
&mut self,
heap: &mut indexed::Min<P, C>,
len: C,
seed: impl planes::Seed<T>,
) -> Result<&mut Self, planes::Error<C>> {
let old = self.entries.len();
let target = len.len();
if target <= old {
return Ok(self);
}
let mut next = indexed::Min::try_new(len).map_err(planes::Error::Heap)?;
{
let source = seed;
self.entries
.try_grow(target - old)
.map_err(|error| planes::Error::Values {
capacity: len,
error,
})?;
for index in old..target {
unsafe {
let compact = links::Index::new_usize(index);
let value = source.seed(compact);
self.entries.vacancy().insert(Node::new(compact, value));
}
}
}
while let Some(timer) = heap.first_entry() {
let index = unsafe { links::Index::new_usize(timer.index()) };
let entry = Entry::<T, PLANES>::new(self, index);
let priority = timer.take();
let live =
unsafe { crate::depot::raw::Proof::new(((&mut next, entry), index.position())) };
let slot = indexed::Slot::<_, _, _, indexed::Empty>::from_source(live);
let (vacant, _) = slot.entry();
vacant.set(priority);
}
*heap = next;
Ok(self)
}
unsafe fn link_prefix<const PLANE: usize>(&mut self, len: usize) {
const { assert!(PLANE < PLANES) };
for index in 0..len {
let index = unsafe { links::Index::new_usize(index) };
Entry::<_, PLANES, phase::Vacant<PLANE>>::new(self, index).link_back();
}
}
}
const _: () = {
assert!(
mem::size_of::<planes::Set<(), 3, indexed::Min<u64>>>()
== mem::size_of::<planes::Set<(), 3>>() + mem::size_of::<indexed::Min<u64>>()
);
assert!(mem::size_of::<planes::Entry<'static, (), 3>>() == 2 * mem::size_of::<usize>());
};
impl<T, P: Ord, const PLANES: usize, const MAX: usize>
Set<T, PLANES, indexed::Min<P, capacity::Limit<MAX>>>
{
pub fn try_seed_in<const PLANE: usize>(
capacity: capacity::Limit<MAX>,
seed: impl Seed<T>,
) -> Result<Self, Error<capacity::Limit<MAX>>> {
let index = indexed::Min::try_new(capacity).map_err(Error::Heap)?;
let values = Set::<T, PLANES>::try_seed(capacity.get(), seed)
.map_err(|error| Error::Values { capacity, error })?;
let mut values = Self {
core: values.core,
index,
};
unsafe { values.core.link_prefix::<PLANE>(capacity.get()) };
Ok(values)
}
}
impl<T, P: Ord, R, const PLANES: usize, const MAX: usize, const N: usize, const MULTIPLIER: usize>
TryFrom<Set<T, PLANES, indexed::Min<P, capacity::Limit<MAX>>>>
for Set<T, PLANES, groups::Index<P, capacity::Limit<MAX>, R, N, MULTIPLIER>>
{
type Error = alloc::Error;
fn try_from(
source: Set<T, PLANES, indexed::Min<P, capacity::Limit<MAX>>>,
) -> Result<Self, Self::Error> {
let records = groups::Index::<P, _, R, N, MULTIPLIER>::reserve(source.index.capacity())?;
Ok(Self {
core: source.core,
index: groups::Index {
priority: source.index,
records,
},
})
}
}
impl<T, P: Ord, R, const PLANES: usize, const MAX: usize, const N: usize, const MULTIPLIER: usize>
Set<T, PLANES, groups::Index<P, capacity::Limit<MAX>, R, N, MULTIPLIER>>
{
pub fn try_replace<const PLANE: usize>(
&mut self,
records: runtime::Fifo<
R,
groups::Rows<capacity::Limit<MAX>, N>,
groups::Buckets<capacity::Limit<MAX>, MULTIPLIER>,
links::List,
>,
seed: impl Seed<T>,
) -> Result<impl FnOnce() + '_, Error<capacity::Limit<MAX>>> {
let capacity = records.capacity().0;
let target = &mut self.index.records;
let core = self
.core
.grow_with(&mut self.index.priority, capacity, seed)?;
Ok(move || {
core.clear::<PLANE>();
unsafe { core.link_prefix::<PLANE>(capacity.get()) };
*target = records;
})
}
pub fn limit(&self) -> capacity::Limit<MAX> {
self.index.records.capacity().0
}
pub fn heap(&self) -> &indexed::Min<P, capacity::Limit<MAX>> {
&self.index.priority
}
pub fn first(
&mut self,
) -> Option<(
indexed::Occupied<'_, P, capacity::Limit<MAX>>,
Entry<'_, T, PLANES>,
)> {
self.core.first(&mut self.index.priority)
}
}