use std::mem;
use crate::depot::{self, capacity};
#[derive(Clone, Copy)]
#[repr(C)]
pub struct State<W> {
head: W,
len: W,
}
impl State<u32> {
pub(in crate::depot::queue::ring) const fn count(self) -> capacity::Count {
capacity::Count::new(self.len)
}
}
impl<W: depot::raw::Word> State<W> {
pub(crate) const EMPTY: Self = Self {
head: W::ZERO,
len: W::ZERO,
};
pub(crate) fn head(self) -> usize {
self.head.offset()
}
pub(crate) fn len(self) -> usize {
self.len.offset()
}
pub fn is_empty(self) -> bool {
self.len() == 0
}
pub(crate) fn is_full(self, capacity: usize) -> bool {
self.len() == capacity
}
pub(crate) unsafe fn position(self, capacity: usize, offset: usize) -> usize {
let suffix = capacity - self.head();
if offset < suffix {
self.head() + offset
} else {
offset - suffix
}
}
pub(crate) fn prefix(self, capacity: usize, len: usize) -> (usize, [usize; 2]) {
let head = self.head();
let first = len.min(capacity - head);
(head, [first, len - first])
}
pub(crate) unsafe fn extend(&mut self, capacity: usize, len: usize) -> (usize, [usize; 2]) {
let tail = unsafe { self.position(capacity, self.len()) };
let added = Self {
head: unsafe { W::from_offset(tail) },
len: unsafe { W::from_offset(len) },
};
self.len = unsafe { W::from_offset(self.len() + len) };
added.prefix(capacity, len)
}
pub(crate) unsafe fn consume(&mut self, capacity: usize, len: usize) {
let left = self.len() - len;
let head = if left == 0 {
0
} else {
unsafe { self.position(capacity, len) }
};
self.head = unsafe { W::from_offset(head) };
self.len = unsafe { W::from_offset(left) };
}
pub(in crate::depot) unsafe fn push<const FRONT: bool>(&mut self, capacity: usize) -> usize {
if !FRONT {
return unsafe { self.extend(capacity, 1) }.0;
}
let head = if self.head() == 0 {
capacity - 1
} else {
self.head() - 1
};
self.head = unsafe { W::from_offset(head) };
self.len = unsafe { W::from_offset(self.len() + 1) };
head
}
pub(crate) unsafe fn pop_front(&mut self, capacity: usize) -> usize {
let index = self.head();
let next = index + 1;
self.head = unsafe { W::from_offset(if next == capacity { 0 } else { next }) };
self.len = unsafe { W::from_offset(self.len() - 1) };
index
}
}
const _: () = {
assert!(mem::size_of::<State<u32>>() == mem::size_of::<u64>());
assert!(mem::size_of::<State<usize>>() == 2 * mem::size_of::<usize>());
};