#![no_std]
extern crate alloc;
use core::{
cmp,
fmt::Debug,
marker::PhantomData,
mem::{self, ManuallyDrop},
ops::{Deref, DerefMut, Index, IndexMut},
ptr,
slice::SliceIndex,
};
struct HeaderVecHeader<H> {
head: H,
capacity: usize,
len: usize,
}
pub struct HeaderVec<H, T> {
ptr: *mut T,
_phantom: PhantomData<H>,
}
impl<H, T> HeaderVec<H, T> {
pub fn new(head: H) -> Self {
Self::with_capacity(1, head)
}
pub fn with_capacity(capacity: usize, head: H) -> Self {
assert!(capacity > 0, "HeaderVec capacity cannot be 0");
let layout = Self::layout(capacity);
let ptr = unsafe { alloc::alloc::alloc(layout) } as *mut T;
if ptr.is_null() {
alloc::alloc::handle_alloc_error(layout);
}
let mut this = Self {
ptr,
_phantom: PhantomData,
};
let header = this.header_mut();
unsafe { core::ptr::write(&mut header.head, head) };
header.capacity = capacity;
header.len = 0;
this
}
#[inline(always)]
pub fn len(&self) -> usize {
self.header().len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn capacity(&self) -> usize {
self.header().capacity
}
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.start_ptr(), self.len()) }
}
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { core::slice::from_raw_parts_mut(self.start_ptr_mut(), self.len()) }
}
#[inline(always)]
pub fn ptr(&self) -> *const () {
self.ptr as *const ()
}
#[inline(always)]
pub fn is(&self, ptr: *const ()) -> bool {
self.ptr as *const () == ptr
}
#[inline(always)]
pub unsafe fn weak(&self) -> HeaderVecWeak<H, T> {
HeaderVecWeak {
header_vec: ManuallyDrop::new(Self {
ptr: self.ptr,
_phantom: PhantomData,
}),
}
}
#[inline(always)]
pub unsafe fn update(&mut self, weak: HeaderVecWeak<H, T>) {
self.ptr = weak.ptr;
}
#[cold]
fn resize_insert(&mut self) -> Option<*const ()> {
let old_capacity = self.capacity();
let new_capacity = old_capacity * 2;
self.header_mut().capacity = new_capacity;
let ptr = unsafe {
alloc::alloc::realloc(
self.ptr as *mut u8,
Self::layout(old_capacity),
Self::elems_to_mem_bytes(new_capacity),
) as *mut T
};
if ptr.is_null() {
alloc::alloc::handle_alloc_error(Self::layout(new_capacity));
}
let previous_pointer = if ptr != self.ptr {
Some(self.ptr as *const ())
} else {
None
};
self.ptr = ptr;
previous_pointer
}
pub fn push(&mut self, item: T) -> Option<*const ()> {
let old_len = self.len();
let new_len = old_len + 1;
let old_capacity = self.capacity();
let previous_pointer = if new_len > old_capacity {
self.resize_insert()
} else {
None
};
unsafe {
core::ptr::write(self.start_ptr_mut().add(old_len), item);
}
self.header_mut().len = new_len;
previous_pointer
}
pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
let mut head = 0;
let original_len = self.len();
let start_ptr = self.start_ptr_mut();
for index in 0..original_len {
unsafe {
if f(&*start_ptr.add(index)) {
if head != index {
ptr::copy_nonoverlapping(start_ptr.add(index), start_ptr.add(head), 1);
}
head += 1;
} else {
ptr::drop_in_place(start_ptr.add(index));
}
}
}
self.header_mut().len = head;
}
#[inline(always)]
fn offset() -> usize {
(mem::size_of::<HeaderVecHeader<H>>() + mem::size_of::<T>() - 1) / mem::size_of::<T>()
}
#[inline(always)]
fn elems_to_mem_elems(capacity: usize) -> usize {
Self::offset() + capacity
}
#[inline(always)]
fn elems_to_mem_bytes(capacity: usize) -> usize {
Self::elems_to_mem_elems(capacity) * mem::size_of::<T>()
}
#[inline(always)]
fn layout(capacity: usize) -> alloc::alloc::Layout {
alloc::alloc::Layout::from_size_align(
Self::elems_to_mem_bytes(capacity),
cmp::max(mem::align_of::<H>(), mem::align_of::<T>()),
)
.expect("unable to produce memory layout with Hrc key type (is it a zero sized type? they are not permitted)")
}
#[inline(always)]
fn start_ptr(&self) -> *const T {
unsafe { self.ptr.add(Self::offset()) }
}
#[inline(always)]
fn start_ptr_mut(&mut self) -> *mut T {
unsafe { self.ptr.add(Self::offset()) }
}
#[inline(always)]
fn header(&self) -> &HeaderVecHeader<H> {
unsafe { &*(self.ptr as *const HeaderVecHeader<H>) }
}
#[inline(always)]
fn header_mut(&mut self) -> &mut HeaderVecHeader<H> {
unsafe { &mut *(self.ptr as *mut HeaderVecHeader<H>) }
}
}
impl<H, T> Drop for HeaderVec<H, T> {
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(&mut self.header_mut().head);
for ix in 0..self.len() {
ptr::drop_in_place(self.start_ptr_mut().add(ix));
}
alloc::alloc::dealloc(self.ptr as *mut u8, Self::layout(self.capacity()));
}
}
}
impl<H, T> Deref for HeaderVec<H, T> {
type Target = H;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.header().head
}
}
impl<H, T> DerefMut for HeaderVec<H, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.header_mut().head
}
}
impl<H, T, I> Index<I> for HeaderVec<H, T>
where
I: SliceIndex<[T]>,
{
type Output = I::Output;
#[inline(always)]
fn index(&self, index: I) -> &I::Output {
self.as_slice().index(index)
}
}
impl<H, T, I> IndexMut<I> for HeaderVec<H, T>
where
I: SliceIndex<[T]>,
{
#[inline(always)]
fn index_mut(&mut self, index: I) -> &mut I::Output {
self.as_mut_slice().index_mut(index)
}
}
impl<H, T> PartialEq for HeaderVec<H, T>
where
H: PartialEq,
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.header().head == other.header().head && self.as_slice() == other.as_slice()
}
}
impl<H, T> Clone for HeaderVec<H, T>
where
H: Clone,
T: Clone,
{
fn clone(&self) -> Self {
let mut new_vec = Self::with_capacity(self.len(), self.header().head.clone());
for e in self.as_slice() {
new_vec.push(e.clone());
}
new_vec
}
}
impl<H, T> Debug for HeaderVec<H, T>
where
H: Debug,
T: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("HeaderVec")
.field("header", &self.header().head)
.field("vec", &self.as_slice())
.finish()
}
}
pub struct HeaderVecWeak<H, T> {
header_vec: ManuallyDrop<HeaderVec<H, T>>,
}
impl<H, T> Deref for HeaderVecWeak<H, T> {
type Target = HeaderVec<H, T>;
fn deref(&self) -> &Self::Target {
&self.header_vec
}
}
impl<H, T> DerefMut for HeaderVecWeak<H, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.header_vec
}
}
impl<H, T> Debug for HeaderVecWeak<H, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("HeaderVecWeak").finish()
}
}