use core::marker::PhantomData;
use core::mem;
use allocator_api2::alloc::{AllocError, Allocator, Global};
use crate::Arena;
use crate::internal::arena_buf::ArenaBuf;
use crate::internal::constants::buffer_freezable;
mod basic;
mod collect_in;
mod drain;
mod freeze;
mod from_in;
mod from_iterator_in;
mod into_iter;
mod mutate;
mod splice;
mod traits;
mod vec_macro;
pub use collect_in::CollectIn;
pub use drain::Drain;
pub use from_iterator_in::FromIteratorIn;
pub use into_iter::IntoIter;
pub use splice::Splice;
#[doc(inline)]
pub use crate::__multitude_vec as vec;
pub struct Vec<'a, T, A: Allocator + Clone = Global> {
buf: ArenaBuf<'a, T>,
arena: &'a Arena<A>,
_phantom: PhantomData<*const T>,
}
impl<'a, T, A: Allocator + Clone> Vec<'a, T, A> {
#[inline]
const fn from_buf(buf: ArenaBuf<'a, T>, arena: &'a Arena<A>) -> Self {
Self {
buf,
arena,
_phantom: PhantomData,
}
}
#[inline]
pub(crate) const fn arena(&self) -> &'a Arena<A> {
self.arena
}
#[cold]
#[inline(never)]
#[cfg_attr(test, mutants::skip)] fn try_grow_to(&mut self, new_cap: usize) -> Result<(), AllocError> {
if const { mem::size_of::<T>() == 0 } {
return Ok(());
}
debug_assert!(new_cap > self.buf.cap(), "try_grow_to: callers must ensure new_cap > current cap");
let payload_bytes = mem::size_of::<T>().checked_mul(new_cap).ok_or(AllocError)?;
let refill_hint = if const { buffer_freezable::<T>() } {
crate::arena::alloc_prefixed::worst_case_strong_slice_payload::<crate::internal::thin_dst::AtomicStrong, T>(new_cap)
} else {
payload_bytes.checked_add(mem::align_of::<T>()).ok_or(AllocError)?
};
let old_cap = self.buf.cap();
if old_cap > 0 {
let elem = mem::size_of::<T>();
let base = self.buf.as_ptr() as usize;
if let (Some(old_bytes), Some(new_bytes)) = (old_cap.checked_mul(elem), new_cap.checked_mul(elem))
&& self.arena.try_grow_local_in_place(base, old_bytes, new_bytes)
{
unsafe { self.buf.set_cap(new_cap) };
return Ok(());
}
}
let uninit = loop {
let reserved = if const { buffer_freezable::<T>() } {
self.arena.try_reserve_freezable_slice::<T>(new_cap)
} else {
self.arena.try_reserve_local_slice::<T>(new_cap)
};
if let Some(u) = reserved {
break u;
}
if self.arena.is_oversized(refill_hint) {
let (new_ptr, new_cap_actual) = self.arena.alloc_oversized_local_with(refill_hint, |mutator| {
let ticket = if const { buffer_freezable::<T>() } {
mutator.try_alloc_freezable_slice::<T>(new_cap)
} else {
mutator.try_alloc_uninit_slice::<T>(new_cap)
};
ticket
.expect("dedicated oversized chunk sized to fit growable buffer")
.into_raw_buffer()
})?;
#[cfg(feature = "stats")]
if old_cap > 0 {
self.arena.record_relocation();
}
unsafe { self.buf.replace_buffer_raw(new_ptr, new_cap_actual) };
return Ok(());
}
self.arena.refill(refill_hint)?;
};
#[cfg(feature = "stats")]
if old_cap > 0 {
self.arena.record_relocation();
}
self.buf.replace_buffer(uninit);
Ok(())
}
}
impl<T, A: Allocator + Clone> Drop for Vec<'_, T, A> {
#[inline]
fn drop(&mut self) {
self.buf.truncate(0);
let _ = self.reclaim_capacity_tail(0);
}
}