use crate::*;
use crate::meta::*;
use core::alloc::Layout;
use core::mem::{MaybeUninit, size_of};
use core::ptr::NonNull;
const _HEAP_MAXREQ : usize = usize::MAX & !0x1F;
#[doc = include_str!("_refs.md")]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct AlignedMalloc;
impl AlignedMalloc {
fn fix_layout(layout: Layout) -> Result<Layout, ()> {
if cfg!(target_os = "macos") { if layout.align() > Self::MAX_ALIGN.as_usize() { return Err(()) } let layout = layout.align_to(size_of::<*const ()>()).map_err(|_| {})?; let layout = layout.pad_to_align(); Ok(layout)
} else {
Ok(layout)
}
}
}
impl Meta for AlignedMalloc {
type Error = ();
const MAX_ALIGN : Alignment = if cfg!(target_os = "macos") { ALIGN_MIN_2_GiB_MAX } else { Alignment::MAX };
const MAX_SIZE : usize = usize::MAX;
#[doc = include_str!("_refs.md")]
const ZST_SUPPORTED : bool = false;
}
unsafe impl Stateless for AlignedMalloc {}
#[doc = include_str!("_refs.md")]
unsafe impl fat::Alloc for AlignedMalloc {
#[track_caller] fn alloc_uninit(&self, layout: Layout) -> Result<NonNull<MaybeUninit<u8>>, Self::Error> {
let layout = Self::fix_layout(layout)?;
#[cfg( target_env = "msvc") ] let alloc = unsafe { ffi::_aligned_malloc(layout.size(), layout.align()) };
#[cfg(not(target_env = "msvc"))] let alloc = unsafe { ffi::aligned_alloc(layout.align(), layout.size()) };
NonNull::new(alloc.cast()).ok_or(())
}
#[cfg(target_env = "msvc")]
#[track_caller] fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<u8>, Self::Error> {
let layout = Self::fix_layout(layout)?;
let alloc = unsafe { ffi::_aligned_recalloc(core::ptr::null_mut(), 1, layout.size(), layout.align()) };
NonNull::new(alloc.cast()).ok_or(())
}
}
#[doc = include_str!("_refs.md")]
#[allow(clippy::missing_safety_doc)]
unsafe impl fat::Free for AlignedMalloc {
#[track_caller] unsafe fn free(&self, ptr: NonNull<MaybeUninit<u8>>, _layout: Layout) {
let _layout = Self::fix_layout(_layout);
#[cfg(all(c23, not(target_env = "msvc")))] if let Ok(_layout) = _layout {
return unsafe { ffi::free_aligned_sized(ptr.as_ptr().cast(), _layout.align(), _layout.size()) };
}
#[cfg(not(target_env = "msvc"))] unsafe { ffi::free(ptr.as_ptr().cast()) }
#[cfg(target_env = "msvc")] unsafe { ffi::_aligned_free(ptr.as_ptr().cast()) }
}
}
#[doc = include_str!("_refs.md")]
#[allow(clippy::missing_safety_doc)]
unsafe impl fat::Realloc for AlignedMalloc {
#[cfg(target_env = "msvc")]
#[track_caller] unsafe fn realloc_uninit(&self, ptr: AllocNN, old_layout: Layout, new_layout: Layout) -> Result<AllocNN, Self::Error> {
let new_layout = Self::fix_layout(new_layout)?;
if new_layout.size() == 0 {
let alloc = fat::Alloc::alloc_uninit(self, new_layout)?;
unsafe { fat::Free::free(self, ptr, old_layout) };
Ok(alloc)
} else {
let alloc = unsafe { ffi::_aligned_realloc(ptr.as_ptr().cast(), new_layout.size(), new_layout.align()) };
NonNull::new(alloc.cast()).ok_or(())
}
}
#[cfg(target_env = "msvc")]
unsafe fn realloc_zeroed(&self, ptr: AllocNN, old_layout: Layout, new_layout: Layout) -> Result<AllocNN, Self::Error> {
let new_layout = Self::fix_layout(new_layout)?;
if new_layout.size() == 0 {
let alloc = fat::Alloc::alloc_zeroed(self, new_layout)?;
unsafe { fat::Free::free(self, ptr, old_layout) };
Ok(alloc.cast())
} else {
let alloc = unsafe { ffi::_aligned_recalloc(ptr.as_ptr().cast(), 1, new_layout.size(), new_layout.align()) };
NonNull::new(alloc.cast()).ok_or(())
}
}
}
#[doc = include_str!("_refs.md")]
#[allow(clippy::missing_safety_doc)]
unsafe impl thin::Free for AlignedMalloc {
#[track_caller] unsafe fn free_nullable(&self, ptr: *mut MaybeUninit<u8>) {
#[cfg(not(target_env = "msvc"))] unsafe { ffi::free(ptr.cast()) }
#[cfg( target_env = "msvc") ] unsafe { ffi::_aligned_free(ptr.cast()) }
}
}
mod ffi {
pub use libc::*;
#[allow(unused_imports)] use core::ptr::NonNull;
#[cfg(not(target_env = "msvc"))] extern "C" {
#[cfg(any(c11, cpp17))] pub fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void;
#[cfg(any(c23 ))] pub fn free_sized(ptr: *mut c_void, size: size_t) -> *mut c_void;
#[cfg(any(c23 ))] pub fn free_aligned_sized(ptr: *mut c_void, alignment: size_t, size: size_t) -> *mut c_void;
}
#[cfg(target_env = "msvc")] extern "cdecl" {
pub fn _aligned_free(block: *mut c_void);
pub fn _aligned_malloc(size: size_t, alignment: size_t) -> *mut c_void;
pub fn _aligned_offset_malloc(size: size_t, alignment: size_t, offset: size_t) -> *mut c_void;
pub fn _aligned_msize(block: NonNull<c_void>, alignment: size_t, offset: size_t) -> size_t;
pub fn _aligned_offset_realloc(block: *mut c_void, size: size_t, alignment: size_t, offset: size_t) -> *mut c_void;
pub fn _aligned_offset_recalloc(block: *mut c_void, count: size_t, size: size_t, alignment: size_t, offset: size_t) -> *mut c_void;
pub fn _aligned_realloc(block: *mut c_void, size: size_t, alignment: size_t) -> *mut c_void;
pub fn _aligned_recalloc(block: *mut c_void, count: size_t, size: size_t, alignment: size_t) -> *mut c_void;
}
#[cfg(never)] #[cfg(target_env = "msvc")] extern "cdecl" {
pub fn _aligned_free_dbg(block: *mut c_void);
pub fn _aligned_malloc_dbg(size: size_t, alignment: size_t, file_name: abistr::CStrPtr<u8>, line_number: c_int) -> *mut c_void;
pub fn _aligned_msize_dbg(block: NonNull<c_void>, alignment: size_t, offset: size_t) -> size_t;
pub fn _aligned_offset_malloc_dbg(size: size_t, alignment: size_t, offset: size_t, file_name: abistr::CStrPtr<u8>, line_number: c_int) -> *mut c_void;
pub fn _aligned_offset_realloc_dbg(block: *mut c_void, size: size_t, alignment: size_t, offset: size_t, file_name: abistr::CStrPtr<u8>, line_number: c_int) -> *mut c_void;
pub fn _aligned_offset_recalloc_dbg(block: *mut c_void, count: size_t, size: size_t, alignment: size_t, offset: size_t, file_name: abistr::CStrPtr<u8>, line_number: c_int) -> *mut c_void;
pub fn _aligned_realloc_dbg(block: *mut c_void, size: size_t, alignment: size_t, file_name: abistr::CStrPtr<u8>, line_number: c_int) -> *mut c_void;
pub fn _aligned_recalloc_dbg(block: *mut c_void, count: size_t, size: size_t, alignment: size_t, file_name: abistr::CStrPtr<u8>, line_number: c_int) -> *mut c_void;
}
}
#[cfg(test)] const ALIGNED_ALLOC_ZERO_INITS : bool = cfg!(any(
target_os = "linux", target_os = "macos", ));
#[test] fn fat_alignment() { fat::test::alignment(AlignedMalloc) }
#[test] fn fat_edge_case_sizes() { fat::test::edge_case_sizes(AlignedMalloc) }
#[test] fn fat_uninit() { if !ALIGNED_ALLOC_ZERO_INITS { unsafe { fat::test::uninit_alloc_unsound(AlignedMalloc) } } }
#[test] fn fat_uninit_realloc() { fat::test::uninit_realloc(AlignedMalloc) }
#[test] fn fat_zeroed() { fat::test::zeroed_alloc(AlignedMalloc) }
#[test] fn fat_zeroed_realloc() { fat::test::zeroed_realloc(AlignedMalloc) }
#[test] fn fat_zst_support() { fat::test::zst_supported_conservative(AlignedMalloc) }