use alloc::*;
use core::{marker::PhantomData, mem, ptr::NonNull, slice};
use slot::Slot;
use ::ptr::Unique;
/// Raw growable array, a low-level utility type to allocate a buffer of memory and not need to worry about edge cases
///
/// It never inspects the memory it holds; it merely allocates enough memory to hold however many elements, and deallocates on `drop` but not `drop`s its contents.
#[allow(missing_debug_implementations)]
pub struct RawVec<T, A: Alloc = ::DefaultA> {
pub(crate) ptr: Unique<T>,
pub(crate) cap: usize,
pub(crate) alloc: A
}
impl<T, A: Alloc> RawVec<T, A> {
/// Make a new array.
#[inline]
pub const fn new_in(a: A) -> Self { RawVec { ptr: Unique::empty(), cap: 0, alloc: a } }
/// Make a new array with enough room to hold at least `cap` elements.
///
/// # Failures
///
/// Returns `None` if allocation fails.
#[inline]
pub fn with_capacity_in(a: A, cap: usize) -> Option<Self> {
RawRawVec::with_capacity_in(a, Layout::new::<T>(), cap).map(|RawRawVec { ptr, cap, alloc }| Self { ptr: ptr.cast().into(), cap, alloc })
}
/// Return number of elements array can hold before reallocation.
#[inline] pub fn capacity(&self) -> usize { self.cap }
#[inline] pub unsafe fn storage_mut(&mut self) -> &mut [T] {
slice::from_raw_parts_mut(self.ptr.as_ptr().as_ptr(), self.cap)
}
#[inline] pub unsafe fn storage(&self) -> &[T] {
slice::from_raw_parts(self.ptr.as_ptr().as_ptr(), self.cap)
}
#[inline] pub fn ptr(&self) -> *mut T { self.ptr.as_ptr().as_ptr() as *const T as *mut T }
/// Make sure the array has enough room for at least `n_more` more elements, assuming it
/// already holds `n`, reallocating if need be.
///
/// # Failures
///
/// Returns `false` if allocation fails, `true` otherwise.
pub fn reserve(&mut self, n: usize, n_more: usize) -> bool {
0 == mem::size_of::<T>() ||
unsafe { self.as_raw_raw_mut().reserve(Layout::new::<T>(), n, n_more) }
}
/// Relinquish memory so capacity = `n`.
pub fn relinquish(&mut self, n: usize) -> bool {
0 == mem::size_of::<T>() ||
unsafe { self.as_raw_raw_mut().relinquish(Layout::new::<T>(), n) }
}
pub fn grow(&mut self, cap: usize) -> bool {
0 == mem::size_of::<T>() ||
unsafe { self.as_raw_raw_mut().grow(Layout::new::<T>(), cap) }
}
#[inline]
pub unsafe fn from_raw_parts_in(alloc: A, ptr: *mut T, cap: usize) -> Self {
RawVec { ptr: Unique::new_unchecked(ptr), cap, alloc }
}
#[inline]
pub unsafe fn alloc_mut(&mut self) -> &mut A { &mut self.alloc }
#[inline]
unsafe fn as_raw_raw_mut(&mut self) -> &mut RawRawVec<A> { mem::transmute(self) }
}
struct RawRawVec<A: Alloc> {
ptr: NonNull<u8>,
cap: usize,
alloc: A
}
impl<A: Alloc> RawRawVec<A> {
fn with_capacity_in(mut a: A, layout: Layout, cap: usize) -> Option<Self> { unsafe {
let empty = mem::transmute(layout.align());
if layout.size() == 0 || cap == 0 { Some(Self { ptr: empty, cap, alloc: a }) } else {
alloc_array_layout(&mut a, layout, cap).map(|(ptr, cap)| Self { ptr, cap, alloc: a })
}
} }
fn reserve(&mut self, layout: Layout, n: usize, n_more: usize) -> bool {
if self.cap - n < n_more {
self.grow(layout, match n.checked_add(n_more).and_then(|n| n.checked_next_power_of_two()) {
None => return false,
Some(cap) => cap,
})
} else { true }
}
fn relinquish(&mut self, layout: Layout, n: usize) -> bool {
if self.cap == n { return true }
unsafe {
if 0 == n { let _ = dealloc_array_layout(&mut self.alloc, layout, self.ptr, self.cap); }
else { match realloc_array_layout(&mut self.alloc, layout, self.ptr, self.cap, n) {
Some((ptr, _)) => self.ptr = ptr,
None => return false,
} }
}
self.cap = n;
true
}
fn grow(&mut self, layout: Layout, cap: usize) -> bool {
if cap > self.cap {
unsafe { match realloc_array_layout(&mut self.alloc, layout, self.ptr, self.cap, cap) {
Some((ptr, cap)) => { self.ptr = ptr; self.cap = cap; },
None => return false,
} }
}
true
}
fn drop(&mut self, layout: Layout) {
unsafe { if self.cap != 0 { let _ = dealloc_array_layout(&mut self.alloc, layout, self.ptr, self.cap); } }
}
}
#[derive(Debug)]
pub struct FixedStorage<'a, T: 'a>(PhantomData<&'a mut [T]>);
unsafe impl<'a, T> Alloc for FixedStorage<'a, T> {
#[inline]
unsafe fn alloc(&mut self, _: Layout) -> Result<NonNull<u8>, AllocErr> { Err(AllocErr::Unsupported { details: "" }) }
#[inline]
unsafe fn dealloc(&mut self, _: NonNull<u8>, _: Layout) {}
}
impl<'a, T> RawVec<T, FixedStorage<'a, T>> {
#[inline]
pub const fn from_storage(xs: &'a mut [Slot<T>]) -> Self { unsafe {
RawVec { ptr: Unique::new_unchecked(xs.as_ptr() as *const T as *mut T), cap: xs.len(),
alloc: FixedStorage(PhantomData) }
} }
}
impl<'a, T: 'a> RawVec<T, FixedStorage<'a, T>> {
pub const empty: Self = RawVec { ptr: Unique::empty(), cap: 0,
alloc: FixedStorage(PhantomData) };
}
impl<T, A: Alloc + Default> RawVec<T, A> {
/// Make a new array.
#[inline]
pub fn new() -> Self { Self::new_in(A::default()) }
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self {
Self::from_raw_parts_in(A::default(), ptr, cap)
}
}
impl<T, A: Alloc> Drop for RawVec<T, A> {
#[inline]
fn drop(&mut self) {
if mem::size_of::<T>() > 0 { unsafe { self.as_raw_raw_mut().drop(Layout::new::<T>()) } }
}
}
impl<T, A: Alloc + Default> Default for RawVec<T, A> {
#[inline]
fn default() -> Self { RawVec::new() }
}
unsafe fn alloc_array_layout<A: Alloc>(a: &mut A, layout: Layout, n: usize) -> Option<(NonNull<u8>, usize)> {
realloc_array_layout(a, layout, mem::transmute(layout.align()), 0, n)
}
#[inline(always)]
unsafe fn realloc_array_layout<A: Alloc>(a: &mut A, layout: Layout, ptr: NonNull<u8>, m: usize, n: usize) -> Option<(NonNull<u8>, usize)> {
let new_array_layout = layout.repeat(n)?.0;
if 0 == m { a.alloc_excess(new_array_layout) } else {
let old_array_layout = layout.repeat(m)?.0;
a.realloc_excess(ptr, old_array_layout, new_array_layout.size())
}.ok().map(|Excess(p, n)| (p, n / layout.size()))
}
unsafe fn dealloc_array_layout<A: Alloc>(a: &mut A, layout: Layout, ptr: NonNull<u8>, n: usize) -> Option<()> {
let array_layout = layout.repeat(n)?.0;
Some(a.dealloc(ptr, array_layout))
}