use std::{mem, num::NonZeroUsize, ptr};
use super::borrow::ReusableMemoryBorrow;
const fn align_up(base: usize, align: usize) -> usize {
base.wrapping_add(align.wrapping_sub(1)) & !align.wrapping_sub(1)
}
macro_rules! impl_borrow_mut_X_as {
(
pub fn $capacity_name: ident;
pub fn $name: ident<$($gen_name: ident),+>[$count: literal];
) => {
pub fn $capacity_name<$($gen_name),+>(
&self, capacity: [NonZeroUsize; $count]
) -> usize {
let align_of: [usize; $count] = [$(mem::align_of::<$gen_name>()),+];
$(
assert_ne!(mem::size_of::<$gen_name>(), 0);
)+
let needed_bytes = 0;
let counter = 0;
$(
#[allow(non_snake_case)]
let $gen_name: (usize, usize) = (align_up(needed_bytes, mem::align_of::<$gen_name>()), counter);
let needed_bytes = $gen_name.0 + mem::size_of::<$gen_name>() * capacity[counter].get();
#[allow(unused_variables)]
let counter = counter + 1;
)+
let align_bump = if mem::align_of::<B>() >= mem::align_of::<T>() {
0
} else {
align_of[0] - 1
};
let needed_bytes = needed_bytes + align_bump;
let needed_length = (needed_bytes + mem::size_of::<B>() - 1) / mem::size_of::<B>();
needed_length
}
pub fn $name<'mem, $($gen_name),+>(
&'mem mut self, capacity: [NonZeroUsize; $count]
) ->( $(ReusableMemoryBorrow<'mem, $gen_name>),+ ) {
let align_of: [usize; $count] = [$(mem::align_of::<$gen_name>()),+];
$(
assert_ne!(mem::size_of::<$gen_name>(), 0);
)+
let needed_bytes = 0;
let counter = 0;
$(
#[allow(non_snake_case)]
let $gen_name: (usize, usize) = (align_up(needed_bytes, mem::align_of::<$gen_name>()), counter);
let needed_bytes = $gen_name.0 + mem::size_of::<$gen_name>() * capacity[counter].get();
#[allow(unused_variables)]
let counter = counter + 1;
)+
let align_bump = if mem::align_of::<B>() >= mem::align_of::<T>() {
0
} else {
align_of[0] - 1
};
let needed_bytes = needed_bytes + align_bump;
let needed_length = (needed_bytes + mem::size_of::<B>() - 1) / mem::size_of::<B>();
self.vec.reserve(needed_length);
let memory_ptr = self.vec.as_mut_ptr();
let align_offset = memory_ptr.align_offset(align_of[0]);
if align_offset == std::usize::MAX {
panic!("Could not align pointer");
}
unsafe {
(
$(
ReusableMemoryBorrow::from_raw_parts(
ptr::NonNull::new_unchecked(
(memory_ptr.add(align_offset) as *mut u8).add($gen_name.0) as *mut $gen_name
),
capacity[$gen_name.1]
)
),+
)
}
}
}
}
#[derive(Debug, Clone)]
pub struct ReusableMemory<B = u8> {
vec: Vec<B>
}
impl<B> ReusableMemory<B> {
impl_borrow_mut_X_as!(
pub fn needed_capacity_for_two;
pub fn borrow_mut_two_as<T, U>[2];
);
impl_borrow_mut_X_as!(
pub fn needed_capacity_for_three;
pub fn borrow_mut_three_as<T, U, V>[3];
);
impl_borrow_mut_X_as!(
pub fn needed_capacity_for_four;
pub fn borrow_mut_four_as<T, U, V, W>[4];
);
impl_borrow_mut_X_as!(
pub fn needed_capacity_for_five;
pub fn borrow_mut_five_as<T, U, V, W, X>[5];
);
pub const unsafe fn new_unchecked() -> Self { ReusableMemory { vec: Vec::new() } }
pub fn new() -> Self { Self::with_capacity(0) }
pub fn with_capacity(len: usize) -> Self {
assert_ne!(mem::size_of::<B>(), 0);
ReusableMemory { vec: Vec::with_capacity(len) }
}
pub fn needed_capacity_for<T>(&self, count: NonZeroUsize) -> usize {
assert_ne!(mem::size_of::<T>(), 0);
let align_bump =
if mem::align_of::<B>() >= mem::align_of::<T>() { 0 } else { mem::align_of::<T>() - 1 };
let needed_length = {
let needed_bytes = mem::size_of::<T>() * count.get() + align_bump;
(needed_bytes + mem::size_of::<B>() - 1) / mem::size_of::<B>()
};
needed_length
}
pub fn borrow_mut_as<'mem, T>(
&'mem mut self, capacity: NonZeroUsize
) -> ReusableMemoryBorrow<'mem, T> {
let needed_length = self.needed_capacity_for::<T>(capacity);
self.vec.reserve(needed_length);
let memory_ptr = self.vec.as_mut_ptr();
let align_offset = memory_ptr.align_offset(mem::align_of::<T>());
if align_offset == std::usize::MAX {
panic!("Could not align pointer");
}
unsafe {
ReusableMemoryBorrow::from_raw_parts(
ptr::NonNull::new_unchecked(memory_ptr.add(align_offset) as *mut T),
capacity
)
}
}
}