use core::{
cell::{Cell, OnceCell, UnsafeCell},
hash::Hash,
marker::PhantomData,
mem::MaybeUninit,
ops::Deref,
ptr::NonNull,
};
#[derive(Debug)]
pub struct LinkVecPtr<T> {
ptr: NonNull<T>,
}
impl<T> Copy for LinkVecPtr<T> { }
impl<T> Clone for LinkVecPtr<T> {
fn clone(&self) -> Self {
Self { ptr: self.ptr }
}
}
impl<T> PartialEq for LinkVecPtr<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T> Eq for LinkVecPtr<T> { }
impl<T> Hash for LinkVecPtr<T> {
#[inline]
fn hash<H>(&self, state: &mut H)
where H: core::hash::Hasher
{
self.ptr.hash(state);
}
}
impl<T> Deref for LinkVecPtr<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
pub struct LinkVec<T, const N: usize = 8> {
head: OnceCell<NonNull<LinkVecNode<T, N>>>,
tail: Cell<Option<NonNull<LinkVecNode<T, N>>>>,
len: Cell<usize>,
}
pub struct LinkVecNode<T, const N: usize = 8> {
next: OnceCell<NonNull<LinkVecNode<T, N>>>,
previous: Option<NonNull<LinkVecNode<T, N>>>,
len: Cell<usize>,
slots: [SlotData<T>; N],
}
struct SlotData<T> {
data: UnsafeCell<MaybeUninit<T>>,
}
impl<T, const N: usize> LinkVec<T, N> {
pub fn leak() -> Self {
Self {
head: OnceCell::new(),
tail: Cell::new(None),
len: Cell::new(0),
}
}
pub fn len(&self) -> usize {
self.len.get()
}
pub unsafe fn unleak(&mut self) {
let mut tail = self.tail.get();
while let Some(next) = tail {
let next_ref = unsafe { next.as_ref() };
tail = next_ref.previous;
if next_ref.len.get() > 0 {
let mut index = next_ref.len.get() - 1;
while index > 0 {
unsafe {
MaybeUninit::assume_init_drop(&mut *next_ref.slots[index].data.get());
}
index -= 1;
}
}
unsafe {
let _ = Box::from_raw(next.as_ptr());
}
}
}
pub fn push(&self, item: T) -> LinkVecPtr<T> {
let mut tail = self.tail.get().unwrap_or_else(|| {
let head = NonNull::new(
Box::into_raw(Box::new(LinkVecNode {
next: OnceCell::new(),
previous: None,
len: Cell::new(0),
slots: [const { SlotData { data: UnsafeCell::new(MaybeUninit::uninit()) } }; N],
}))
)
.expect("LinkVec NonNull head");
self.head.set(head).expect("LinkVec set head");
self.tail.set(Some(head));
head
});
let tail_ref = unsafe { tail.as_ref() };
if tail_ref.len.get() == N {
let new_tail = NonNull::new(
Box::into_raw(Box::new(LinkVecNode {
next: OnceCell::new(),
previous: Some(tail),
len: Cell::new(0),
slots: [const { SlotData { data: UnsafeCell::new(MaybeUninit::uninit()) } }; N],
}))
)
.expect("LinkVec NonNull new tail");
tail_ref.next.set(new_tail).expect("LinkVec set tail.next");
self.tail.set(Some(new_tail));
tail = new_tail;
}
let tail_ref = unsafe { tail.as_ref() };
let index = tail_ref.len.get();
tail_ref.len.set(index + 1);
let slot = &unsafe { tail.as_ref() }.slots[index];
unsafe { &mut *slot.data.get() }.write(item);
self.len.set(self.len.get() + 1);
LinkVecPtr {
ptr: tail_ref.slot_data_ptr(index),
}
}
pub fn iter<'a>(&'a self) -> LinkVecIter<'a, T, N> {
LinkVecIter {
head: self.head.get().copied(),
len: self.len.get(),
node_index: 0,
_lifetime: PhantomData,
}
}
}
impl<T, const N: usize> LinkVecNode<T, N> {
fn slot_data_ptr(&self, index: usize) -> NonNull<T> {
let slot = &self.slots[index];
let ptr = unsafe { &mut *slot.data.get() }.as_mut_ptr();
unsafe { NonNull::new_unchecked(ptr) }
}
}
pub struct LinkVecIter<'a, T, const N: usize> {
head: Option<NonNull<LinkVecNode<T, N>>>,
len: usize,
node_index: usize,
_lifetime: PhantomData<&'a ()>,
}
impl<'a, T: core::fmt::Debug + 'a, const N: usize> Iterator for LinkVecIter<'a, T, N> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let Some(mut head) = self.head else {
return None;
};
let mut head_ref = unsafe { head.as_ref() };
if self.node_index == head_ref.len.get() {
if let Some(next) = head_ref.next.get().copied() {
self.head = Some(next);
self.node_index = 0;
head = next;
head_ref = unsafe { head.as_ref() };
} else {
return None;
}
}
let index = self.node_index;
self.node_index += 1;
self.len -= 1;
let slot_data_ptr = head_ref.slot_data_ptr(index);
Some(unsafe { slot_data_ptr.as_ref() })
}
}
impl<'a, T: core::fmt::Debug + 'a, const N: usize> ExactSizeIterator for LinkVecIter<'a, T, N> {
fn len(&self) -> usize { self.len }
}
impl<T, const N: usize> Clone for LinkVecIter<'_, T, N> {
fn clone(&self) -> Self {
Self {
head: self.head,
len: self.len,
node_index: self.node_index,
_lifetime: PhantomData,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_link_vec_iter() {
let mut l = LinkVec::<u32, 2>::leak();
let n1 = l.push(1);
let n2 = l.push(2);
let n3 = l.push(3);
assert_eq!(*n1, 1);
assert_eq!(*n2, 2);
assert_eq!(*n3, 3);
assert_eq!(l.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3]);
unsafe { l.unleak(); }
}
}