extern crate alloc;
use alloc::alloc::{alloc, alloc_zeroed, dealloc, handle_alloc_error};
use core::alloc::Layout;
use smallvec::SmallVec;
const WORK_ALIGNMENT: usize = 64;
#[derive(Debug)]
pub(super) struct FlatWork {
lanes: usize,
lane_len: usize,
ptr: *mut u8,
len: usize,
}
unsafe impl Send for FlatWork {}
unsafe impl Sync for FlatWork {}
impl FlatWork {
pub(super) fn new(lanes: usize, lane_len: usize) -> Self {
let len = lanes * lane_len;
let layout =
Layout::from_size_align(len, WORK_ALIGNMENT).expect("FlatWork layout overflow");
let ptr = unsafe { alloc_zeroed(layout) };
if ptr.is_null() {
handle_alloc_error(layout);
}
Self {
lanes,
lane_len,
ptr,
len,
}
}
pub(super) unsafe fn new_uninit(lanes: usize, lane_len: usize) -> Self {
let len = lanes * lane_len;
let layout =
Layout::from_size_align(len, WORK_ALIGNMENT).expect("FlatWork layout overflow");
let ptr = unsafe { alloc(layout) };
if ptr.is_null() {
handle_alloc_error(layout);
}
Self {
lanes,
lane_len,
ptr,
len,
}
}
pub(super) fn can_reuse(&self, lanes: usize, lane_len: usize) -> bool {
self.lanes == lanes && self.lane_len == lane_len
}
pub(super) fn lanes(&self) -> usize {
self.lanes
}
pub(super) fn lane_len(&self) -> usize {
self.lane_len
}
pub(super) fn lane(&self, idx: usize) -> &[u8] {
debug_assert!(
idx < self.lanes,
"lane index {idx} out of bounds (lanes={})",
self.lanes
);
let start = idx * self.lane_len;
unsafe { core::slice::from_raw_parts(self.ptr.add(start), self.lane_len) }
}
pub(super) fn lane_mut(&mut self, idx: usize) -> &mut [u8] {
debug_assert!(
idx < self.lanes,
"lane index {idx} out of bounds (lanes={})",
self.lanes
);
let start = idx * self.lane_len;
unsafe { core::slice::from_raw_parts_mut(self.ptr.add(start), self.lane_len) }
}
pub(super) fn with_lane_views<R>(
&mut self,
lanes: usize,
size: usize,
f: impl FnOnce(&mut [&mut [u8]]) -> R,
) -> R {
debug_assert!(
size <= self.lane_len,
"view size {size} exceeds lane_len {}",
self.lane_len
);
debug_assert!(
lanes <= self.lanes,
"requested lanes {lanes} exceeds capacity {}",
self.lanes
);
let mut views: SmallVec<[&mut [u8]; 96]> = (0..lanes)
.map(|i| {
let start = i * self.lane_len;
unsafe {
let ptr = self.ptr.add(start);
&mut *core::ptr::slice_from_raw_parts_mut(ptr, size)
}
})
.collect();
f(&mut views)
}
}
impl Drop for FlatWork {
fn drop(&mut self) {
if self.len > 0 {
let layout = Layout::from_size_align(self.len, WORK_ALIGNMENT)
.expect("FlatWork layout overflow");
unsafe { dealloc(self.ptr, layout) };
}
}
}