#![allow(
clippy::items_after_statements,
clippy::single_match_else,
clippy::panic,
clippy::manual_assert,
clippy::undocumented_unsafe_blocks,
clippy::match_wild_err_arm,
clippy::missing_panics_doc,
clippy::manual_saturating_arithmetic,
clippy::struct_field_names,
reason = "reachable panics are programmer error; keep this close to `allocator_api2::vec::Vec`; `drain_*` names mirror `std::vec::Drain`"
)]
use core::marker::PhantomData;
use core::mem;
use allocator_api2::alloc::{AllocError, Allocator, Global};
use crate::Arena;
use crate::internal::arena_buf::ArenaBuf;
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> {
pub(super) buf: ArenaBuf<'a, T>,
pub(super) arena: &'a Arena<A>,
_phantom: PhantomData<*const T>,
}
impl<'a, T, A: Allocator + Clone> Vec<'a, T, A> {
#[inline]
pub(super) 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)] pub(super) 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 refill_hint = mem::size_of::<T>()
.checked_mul(new_cap)
.and_then(|b| b.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 {
if let Some(u) = self.arena.try_reserve_local_slice::<T>(new_cap) {
break u;
}
if self.arena.is_oversized_local(refill_hint) {
let (new_ptr, new_cap_actual) = self.arena.alloc_oversized_local_with(refill_hint, |mutator| {
let ticket = mutator
.try_alloc_uninit_slice::<T>(new_cap)
.expect("dedicated oversized chunk sized to fit growable buffer");
ticket.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_local(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);
}
}