use std::mem;
use crate::collections;
const NONE: u32 = u32::MAX;
struct Node<T> {
value: mem::MaybeUninit<T>,
next: u32,
}
struct NodePool<T> {
nodes: Box<[mem::MaybeUninit<Node<T>>]>,
free: u32,
initialized: u32,
live: u32,
}
#[derive(Clone, Copy)]
struct ChainState {
head: u32,
tail: u32,
len: u32,
}
impl ChainState {
const EMPTY: Self = Self {
head: NONE,
tail: NONE,
len: 0,
};
}
pub struct Linked<T> {
nodes: NodePool<T>,
lanes: Box<[ChainState]>,
_thread: crate::ThreadBound,
}
pub struct Stack<T> {
nodes: NodePool<T>,
lanes: Box<[u32]>,
}
pub struct StackDrain<'a, T> {
arena: &'a mut Stack<T>,
lane: usize,
}
impl<T> NodePool<T> {
fn with_capacity(capacity: usize) -> Self {
match Self::try_with_capacity(capacity) {
Ok(pool) => pool,
Err(error) => error.abort(),
}
}
fn try_with_capacity(capacity: usize) -> Result<Self, collections::AllocationError> {
assert!(
u32::try_from(capacity).is_ok(),
"linked node capacity overflow"
);
Ok(Self {
nodes: collections::try_box_uninit(capacity)?,
free: NONE,
initialized: 0,
live: 0,
})
}
fn is_full(&self) -> bool {
self.live as usize == self.nodes.len()
}
fn available(&self) -> usize {
self.nodes.len() - self.live as usize
}
fn front<'a>(&'a self, state: &ChainState) -> Option<&'a T> {
self.value(state.head)
}
fn front_mut<'a>(&'a mut self, state: &ChainState) -> Option<&'a mut T> {
self.value_mut(state.head)
}
fn value(&self, index: u32) -> Option<&T> {
if index == NONE {
return None;
}
let node = unsafe { self.node(index) };
Some(unsafe { node.value.assume_init_ref() })
}
fn value_mut(&mut self, index: u32) -> Option<&mut T> {
if index == NONE {
return None;
}
let node = unsafe { self.node_mut(index) };
Some(unsafe { node.value.assume_init_mut() })
}
fn push_back(&mut self, state: &mut ChainState, value: T) -> Result<(), T> {
let index = self.allocate(value)?;
if state.tail == NONE {
state.head = index;
} else {
unsafe { self.node_mut(state.tail) }.next = index;
}
state.tail = index;
state.len += 1;
Ok(())
}
fn push_front(&mut self, state: &mut ChainState, value: T) -> Result<(), T> {
let head = state.head;
let index = self.allocate(value)?;
unsafe { self.node_mut(index) }.next = head;
state.head = index;
if state.tail == NONE {
state.tail = index;
}
state.len += 1;
Ok(())
}
fn pop_front(&mut self, state: &mut ChainState) -> Option<T> {
let index = state.head;
if index == NONE {
return None;
}
let next = unsafe { self.node(index) }.next;
state.head = next;
state.len -= 1;
if next == NONE {
state.tail = NONE;
}
Some(unsafe { self.release(index) })
}
fn push(&mut self, head: &mut u32, value: T) -> Result<(), T> {
let previous = *head;
let index = self.allocate(value)?;
unsafe { self.node_mut(index) }.next = previous;
*head = index;
Ok(())
}
fn pop(&mut self, head: &mut u32) -> Option<T> {
let index = *head;
if index == NONE {
return None;
}
*head = unsafe { self.node(index) }.next;
Some(unsafe { self.release(index) })
}
fn allocate(&mut self, value: T) -> Result<u32, T> {
if self.is_full() {
return Err(value);
}
let index = if self.free == NONE {
let index = self.initialized;
debug_assert!((index as usize) < self.nodes.len());
self.initialized += 1;
self.nodes[index as usize].write(Node {
value: mem::MaybeUninit::new(value),
next: NONE,
});
index
} else {
let index = self.free;
let next = {
let node = unsafe { self.node_mut(index) };
let next = node.next;
node.value.write(value);
node.next = NONE;
next
};
self.free = next;
index
};
self.live += 1;
Ok(index)
}
unsafe fn release(&mut self, index: u32) -> T {
let free = self.free;
let node = unsafe { self.node_mut(index) };
let value = unsafe { node.value.assume_init_read() };
node.next = free;
self.free = index;
self.live -= 1;
value
}
unsafe fn node(&self, index: u32) -> &Node<T> {
debug_assert!(index < self.initialized);
unsafe { self.nodes.get_unchecked(index as usize).assume_init_ref() }
}
unsafe fn node_mut(&mut self, index: u32) -> &mut Node<T> {
debug_assert!(index < self.initialized);
unsafe {
self.nodes
.get_unchecked_mut(index as usize)
.assume_init_mut()
}
}
}
impl<T> Linked<T> {
pub fn with_capacity(capacity: usize, lanes: usize) -> Self {
match Self::try_with_capacity(capacity, lanes) {
Ok(arena) => arena,
Err(error) => error.abort(),
}
}
pub fn try_with_capacity(
capacity: usize,
lanes: usize,
) -> Result<Self, collections::AllocationError> {
use crate::ThreadBound;
Ok(Self {
nodes: NodePool::try_with_capacity(capacity)?,
lanes: collections::try_box_with(lanes, |_| ChainState::EMPTY)?,
_thread: ThreadBound::NEW,
})
}
pub fn is_full(&self) -> bool {
self.nodes.is_full()
}
pub fn lane_len(&self, lane: usize) -> usize {
self.lanes[lane].len as usize
}
pub fn lane_is_empty(&self, lane: usize) -> bool {
self.lanes.get(lane).is_none_or(|state| state.len == 0)
}
pub fn front(&self, lane: usize) -> Option<&T> {
self.nodes.front(self.lanes.get(lane)?)
}
pub fn front_mut(&mut self, lane: usize) -> Option<&mut T> {
self.nodes.front_mut(self.lanes.get(lane)?)
}
pub fn push_back(&mut self, lane: usize, value: T) -> Result<(), T> {
let Some(state) = self.lanes.get_mut(lane) else {
return Err(value);
};
self.nodes.push_back(state, value)
}
pub fn push_front(&mut self, lane: usize, value: T) -> Result<(), T> {
let Some(state) = self.lanes.get_mut(lane) else {
return Err(value);
};
self.nodes.push_front(state, value)
}
pub fn pop_front(&mut self, lane: usize) -> Option<T> {
self.nodes.pop_front(self.lanes.get_mut(lane)?)
}
fn clear(&mut self) {
collections::ClearGuard::run(self, Self::clear_remaining);
}
fn clear_remaining(&mut self) {
for lane in 0..self.lanes.len() {
while let Some(value) = self.pop_front(lane) {
drop(value);
}
}
}
}
impl<T> Drop for Linked<T> {
fn drop(&mut self) {
self.clear();
}
}
impl<T> Stack<T> {
pub fn with_capacity(capacity: usize, lanes: usize) -> Self {
Self {
nodes: NodePool::with_capacity(capacity),
lanes: vec![NONE; lanes].into_boxed_slice(),
}
}
pub fn available(&self) -> usize {
self.nodes.available()
}
pub fn lane_is_empty(&self, lane: usize) -> bool {
self.lanes.get(lane).is_none_or(|head| *head == NONE)
}
pub fn push(&mut self, lane: usize, value: T) -> Result<(), T> {
let Some(head) = self.lanes.get_mut(lane) else {
return Err(value);
};
self.nodes.push(head, value)
}
pub fn pop(&mut self, lane: usize) -> Option<T> {
self.nodes.pop(self.lanes.get_mut(lane)?)
}
pub fn drain(&mut self, lane: usize) -> StackDrain<'_, T> {
StackDrain { arena: self, lane }
}
fn clear(&mut self) {
collections::ClearGuard::run(self, Self::clear_remaining);
}
fn clear_remaining(&mut self) {
for lane in 0..self.lanes.len() {
while let Some(value) = self.pop(lane) {
drop(value);
}
}
}
}
impl<T> Drop for Stack<T> {
fn drop(&mut self) {
self.clear();
}
}
impl<T> Iterator for StackDrain<'_, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.arena.pop(self.lane)
}
}
impl<T> Drop for StackDrain<'_, T> {
fn drop(&mut self) {
collections::ClearGuard::run(self, Self::clear_remaining);
}
}
impl<T> StackDrain<'_, T> {
fn clear_remaining(&mut self) {
for value in self.by_ref() {
drop(value);
}
}
}