use std::alloc::{AllocError, Allocator, Global, Layout};
use std::cmp;
use std::ptr::NonNull;
#[derive(Clone, Copy, Debug, Default)]
pub struct AlignedAlloc<const N: usize, A: Allocator = Global> {
alloc: A,
}
impl<const N: usize, A: Allocator> AlignedAlloc<N, A> {
pub fn new(alloc: A) -> Self {
assert!(N.is_power_of_two(), "alignment must be power of two");
Self { alloc }
}
}
unsafe impl<const N: usize, A: Allocator> Allocator for AlignedAlloc<N, A> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.alloc.allocate(aligned_layout::<N>(layout))
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe {
self.alloc.deallocate(ptr, aligned_layout::<N>(layout));
}
}
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.alloc.allocate_zeroed(aligned_layout::<N>(layout))
}
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
self.alloc.grow(ptr, aligned_layout::<N>(old_layout), aligned_layout::<N>(new_layout))
}
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
self.alloc.grow_zeroed(
ptr,
aligned_layout::<N>(old_layout),
aligned_layout::<N>(new_layout),
)
}
}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
self.alloc.shrink(ptr, aligned_layout::<N>(old_layout), aligned_layout::<N>(new_layout))
}
}
}
fn aligned_layout<const N: usize>(layout: Layout) -> Layout {
let align = cmp::min(N, layout.size().next_power_of_two());
unsafe { Layout::from_size_align_unchecked(layout.size(), cmp::max(layout.align(), align)) }
}