use std::alloc::{self, Layout};
use std::mem;
use std::ptr;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum AlignmentStrategy {
Default,
Simd,
CacheLine,
Custom(usize),
}
pub fn align_data<T: Copy>(data: &mut [T], strategy: AlignmentStrategy) {
let alignment = match strategy {
AlignmentStrategy::Default => mem::align_of::<T>(),
AlignmentStrategy::Simd => get_simd_alignment::<T>(),
AlignmentStrategy::CacheLine => get_cache_line_size(),
AlignmentStrategy::Custom(align) => align,
};
let data_ptr = data.as_ptr() as usize;
if data_ptr.is_multiple_of(alignment) {
return;
}
let size = std::mem::size_of_val(data);
let layout = Layout::from_size_align(size, alignment).unwrap_or_else(|_| Layout::new::<T>());
unsafe {
let new_ptr = alloc::alloc(layout) as *mut T;
if new_ptr.is_null() {
return;
}
ptr::copy_nonoverlapping(data.as_ptr(), new_ptr, data.len());
ptr::copy_nonoverlapping(new_ptr, data.as_mut_ptr(), data.len());
alloc::dealloc(new_ptr as *mut u8, layout);
}
}
#[allow(clippy::nonminimal_bool)]
fn get_simd_alignment<T>() -> usize {
let type_size = mem::size_of::<T>();
let base_alignment = if cfg!(target_arch = "x86_64") {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx512f") {
64 } else if is_x86_feature_detected!("avx2") || is_x86_feature_detected!("avx") {
32 } else if is_x86_feature_detected!("sse2") {
16 } else {
8 }
}
#[cfg(not(target_arch = "x86_64"))]
{
16 }
} else if cfg!(target_arch = "aarch64") {
16
} else {
8
};
base_alignment.max(type_size)
}
fn get_cache_line_size() -> usize {
64 }
pub fn create_aligned_vec<T: Copy>(data: &[T], alignment: usize) -> Vec<T> {
let size = std::mem::size_of_val(data);
let layout = Layout::from_size_align(size, alignment).unwrap_or_else(|_| Layout::new::<T>());
unsafe {
let new_ptr = alloc::alloc(layout) as *mut T;
if new_ptr.is_null() {
return data.to_vec();
}
ptr::copy_nonoverlapping(data.as_ptr(), new_ptr, data.len());
Vec::from_raw_parts(new_ptr, data.len(), data.len())
}
}
pub fn create_aligned_buffer<T: Copy + Default>(size: usize, alignment: usize) -> Vec<T> {
let byte_size = size * mem::size_of::<T>();
let layout = Layout::from_size_align(byte_size, alignment).unwrap_or_else(|_| {
Layout::array::<T>(size).expect("Layout::array should succeed for valid size")
});
unsafe {
let ptr = alloc::alloc_zeroed(layout) as *mut T;
if ptr.is_null() {
return vec![T::default(); size];
}
Vec::from_raw_parts(ptr, size, size)
}
}
pub fn realign_vec<T: Copy>(mut vec: Vec<T>, new_alignment: usize) -> Vec<T> {
if is_aligned(vec.as_ptr(), new_alignment) {
return vec;
}
let aligned_vec = create_aligned_vec(&vec, new_alignment);
vec.clear();
vec.shrink_to_fit();
aligned_vec
}
pub fn is_aligned<T>(ptr: *const T, alignment: usize) -> bool {
(ptr as usize).is_multiple_of(alignment)
}
pub fn alignment_padding(offset: usize, alignment: usize) -> usize {
if offset.is_multiple_of(alignment) {
0
} else {
alignment - (offset % alignment)
}
}
pub fn get_optimal_alignment_for_type<T>() -> usize {
let type_size = mem::size_of::<T>();
if mem::size_of::<T>() == mem::size_of::<f32>() || mem::size_of::<T>() == mem::size_of::<f64>()
{
return get_simd_alignment::<T>();
}
if type_size >= 4 {
return get_simd_alignment::<T>();
}
get_cache_line_size().max(type_size)
}
pub fn align_address(addr: usize, alignment: usize) -> usize {
(addr + alignment - 1) & !(alignment - 1)
}
pub fn is_range_aligned<T>(slice: &[T], alignment: usize) -> bool {
let ptr = slice.as_ptr() as usize;
let size = std::mem::size_of_val(slice);
if !ptr.is_multiple_of(alignment) {
return false;
}
size.is_multiple_of(alignment)
}
pub fn get_alignment_info<T>(data: &[T]) -> AlignmentInfo {
let ptr = data.as_ptr() as usize;
let cache_line_size = get_cache_line_size();
let simd_alignment = get_simd_alignment::<T>();
AlignmentInfo {
address: ptr,
cache_line_aligned: ptr.is_multiple_of(cache_line_size),
simd_aligned: ptr.is_multiple_of(simd_alignment),
natural_aligned: ptr.is_multiple_of(mem::align_of::<T>()),
cache_line_size,
simd_alignment,
type_alignment: mem::align_of::<T>(),
}
}
#[derive(Debug, Clone)]
pub struct AlignmentInfo {
pub address: usize,
pub cache_line_aligned: bool,
pub simd_aligned: bool,
pub natural_aligned: bool,
pub cache_line_size: usize,
pub simd_alignment: usize,
pub type_alignment: usize,
}