#[cfg(feature = "nightly")]
use std::alloc::{Allocator, Global};
use std::{
alloc::Layout,
ptr::{self, NonNull},
};
mod alloc_layout_extra {
use super::*;
pub const fn padding_needed_for(layout: &Layout, align: usize) -> usize {
let len = layout.size();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len)
}
pub fn repeat(layout: &Layout, n: usize) -> Option<(Layout, usize)> {
let padded_size = layout.size() + padding_needed_for(layout, layout.align());
let alloc_size = padded_size.checked_mul(n)?;
let layout = Layout::from_size_align(alloc_size, layout.align()).ok()?;
Some((layout, padded_size))
}
}
pub fn new_slice_layout<T>(capacity: usize) -> (Layout, usize) {
let (layout, len) =
alloc_layout_extra::repeat(&Layout::new::<T>(), capacity).expect("capacity is valid");
if layout.size() == 0 {
panic!("cannot allocate ZST");
}
(layout, len)
}
pub fn alloc_slice<T>(count: usize) -> NonNull<[T]> {
let (layout, _) = new_slice_layout::<T>(count);
let (data, byte_count) = {
#[cfg(feature = "nightly")]
{
let data = Global
.allocate(layout)
.unwrap_or_else(|_| panic!("allocation error"));
(data.cast(), data.len())
}
#[cfg(not(feature = "nightly"))]
{
use std::alloc::alloc;
let data = unsafe { alloc(layout) };
let Some(data) = NonNull::new(data) else {
panic!("allocation error")
};
(data, layout.size())
}
};
unsafe {
let raw = ptr::slice_from_raw_parts_mut(data.as_ptr() as *mut _, byte_count);
NonNull::new_unchecked(raw)
}
}
pub unsafe fn dealloc_slice<T>(ptr: NonNull<[T]>) {
let layout = new_slice_layout::<T>(ptr.len()).0;
#[cfg(feature = "nightly")]
{
Global.deallocate(ptr.cast(), layout);
}
#[cfg(not(feature = "nightly"))]
{
use std::alloc::dealloc;
unsafe {
dealloc(ptr.as_ptr() as *mut _, layout);
}
}
}