use super::alloc_utils::*;
use core::mem;
use core::mem::ManuallyDrop;
use core::ptr;
pub fn block_max_len<E, L>() -> usize {
use core::usize::MAX as MAX_LEN;
let elem_size = mem::size_of::<E>();
let label_size = mem::size_of::<L>();
if elem_size == 0 {
MAX_LEN - 1
} else {
(MAX_LEN - label_size) / elem_size - 1
}
}
#[repr(C)]
pub struct MemBlock<E, L = ()> {
label: ManuallyDrop<L>,
elements: ManuallyDrop<E>,
}
impl<E, L> MemBlock<E, L> {
pub fn memory_layout(len: usize) -> (usize, usize) {
let l_layout = size_align::<Self>();
if len <= 1 {
l_layout
} else {
let d_layout = size_align_array::<E>(len - 1);
size_align_multiple(&[l_layout, size_align::<usize>(), d_layout])
}
}
pub unsafe fn dealloc(&mut self, len: usize) {
ptr::drop_in_place(&mut *self.label);
for i in 0..len {
ptr::drop_in_place(self.get(i));
}
self.dealloc_lazy(len);
}
pub unsafe fn dealloc_lazy(&mut self, len: usize) {
let (size, align) = Self::memory_layout(len);
deallocate(self, size, align);
}
pub unsafe fn new<'a>(label: L, len: usize) -> *mut Self {
#[cfg(not(feature = "no-asserts"))]
assert!(len <= block_max_len::<E, L>());
let (size, align) = Self::memory_layout(len);
let new_ptr = allocate::<Self>(size, align);
ptr::write(&mut (&mut *new_ptr).label, ManuallyDrop::new(label));
new_ptr
}
pub fn new_init<F>(label: L, len: usize, mut func: F) -> *mut Self
where
F: FnMut(&mut L, usize) -> E,
{
let new_ptr = unsafe { &mut *Self::new(label, len) };
for i in 0..len {
let item = func(&mut new_ptr.label, i);
let garbage = mem::replace(unsafe { new_ptr.get(i) }, item);
mem::forget(garbage);
}
new_ptr
}
pub unsafe fn get<'a>(&'a self, idx: usize) -> &'a mut E {
let element = &*self.elements as *const E as *mut E;
let element = element.add(idx);
&mut *element
}
pub unsafe fn get_label<'a>(&'a self) -> &'a mut L {
&mut *(&*self.label as *const L as *mut L)
}
pub unsafe fn iter(&self, len: usize) -> MemBlockIter<E, L> {
let beginning = &*self.elements as *const E as *mut E;
MemBlockIter {
block: self as *const Self as *mut Self,
current: beginning,
end: beginning.add(len),
}
}
pub unsafe fn get_slice<'a>(&'a self, start: usize, end: usize) -> &'a mut [E] {
#[cfg(not(feature = "no-asserts"))]
assert!(start <= end);
core::slice::from_raw_parts_mut(self.get(start) as *mut E, end - start)
}
pub unsafe fn as_slice<'a>(&'a self, len: usize) -> &'a mut [E] {
self.get_slice(0, len)
}
}
impl<E, L> MemBlock<E, L>
where
E: Clone,
L: Clone,
{
pub unsafe fn clone<'a, 'b>(&'a self, len: usize) -> &'b mut Self {
&mut *Self::new_init((*self.label).clone(), len, |_, i| self.get(i).clone())
}
}
pub struct MemBlockIter<E, L> {
block: *mut MemBlock<E, L>,
current: *mut E,
end: *mut E,
}
impl<E, L> Iterator for MemBlockIter<E, L> {
type Item = E;
fn next(&mut self) -> Option<E> {
if self.current == self.end {
None
} else {
unsafe {
let out = ptr::read(self.current);
self.current = self.current.add(1);
Some(out)
}
}
}
}
impl<E, L> Drop for MemBlockIter<E, L> {
fn drop(&mut self) {
unsafe {
let block_ref = &mut *self.block;
ptr::drop_in_place(&mut *block_ref.label);
let len = ((self.end as usize) - (&*block_ref.elements as *const E as usize))
/ mem::size_of::<E>();
(&mut *self.block).dealloc_lazy(len);
}
}
}