use std::{
error::Error,
fmt::{self, Display, Formatter},
ops::{Deref, DerefMut, Range},
};
pub const CACHELINE_BYTES: usize = 64;
pub const DEFAULT_SECTOR_SIZE: usize = 4096;
pub const MIN_SECTOR_SIZE: usize = 512;
#[inline(always)]
pub const fn is_aligned(val: u64, align: u64) -> bool {
if align == 0 {
return false;
}
if align.is_power_of_two() {
(val & (align - 1)) == 0
} else {
val.is_multiple_of(align)
}
}
#[inline(always)]
pub const fn align_down(val: u64, align: u64) -> u64 {
if align <= 1 {
return val;
}
if align.is_power_of_two() {
val & !(align - 1)
} else {
(val / align) * align
}
}
#[inline(always)]
#[must_use]
pub const fn checked_align_up(val: u64, align: u64) -> Option<u64> {
if align <= 1 {
return Some(val);
}
if align.is_power_of_two() {
let mask = align - 1;
if (val & mask) == 0 {
Some(val)
} else {
match val.checked_add(mask) {
Some(v) => Some(v & !mask),
None => None,
}
}
} else {
let rem = val % align;
if rem == 0 {
Some(val)
} else {
val.checked_add(align - rem)
}
}
}
#[inline(always)]
#[must_use]
pub const fn align_up(val: u64, align: u64) -> u64 {
match checked_align_up(val, align) {
Some(v) => v,
None => {
if align.is_power_of_two() {
!(align - 1)
} else {
(u64::MAX / align) * align
}
}
}
}
#[inline(always)]
pub const fn is_cacheline_aligned(val: u64) -> bool {
is_aligned(val, CACHELINE_BYTES as u64)
}
#[inline(always)]
pub const fn align_to_cacheline(val: u64) -> u64 {
align_up(val, CACHELINE_BYTES as u64)
}
#[repr(align(128))]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CachePadded<T>(pub T);
impl<T> CachePadded<T> {
#[inline(always)]
pub const fn new(value: T) -> Self {
Self(value)
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> Deref for CachePadded<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for CachePadded<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<T> for CachePadded<T> {
#[inline(always)]
fn from(val: T) -> Self {
Self::new(val)
}
}
#[repr(align(64))]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CachePadded64<T>(pub T);
impl<T> CachePadded64<T> {
#[inline(always)]
pub const fn new(value: T) -> Self {
Self(value)
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> Deref for CachePadded64<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for CachePadded64<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<T> for CachePadded64<T> {
#[inline(always)]
fn from(val: T) -> Self {
Self::new(val)
}
}
#[inline(always)]
pub const fn is_valid_sector_size(size: usize) -> bool {
size >= MIN_SECTOR_SIZE && size.is_power_of_two()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectorRangeError {
InvalidSectorSize(usize),
Overflow,
}
impl Display for SectorRangeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidSectorSize(s) => {
write!(f, "无效扇区大小: {s},必须为 2 的幂且 >= {MIN_SECTOR_SIZE}")
}
Self::Overflow => write!(f, "扇区范围计算溢出"),
}
}
}
impl Error for SectorRangeError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SectorRange {
pub aligned_offset: u64,
pub aligned_len: usize,
pub internal_offset: usize,
}
impl SectorRange {
pub fn calculate(offset: u64, len: usize, sector_size: usize) -> Result<Self, SectorRangeError> {
if !is_valid_sector_size(sector_size) {
return Err(SectorRangeError::InvalidSectorSize(sector_size));
}
let sector_u64 = sector_size as u64;
let aligned_offset = align_down(offset, sector_u64);
let internal_offset = (offset - aligned_offset) as usize;
if len == 0 {
return Ok(Self {
aligned_offset,
aligned_len: 0,
internal_offset,
});
}
let end = offset
.checked_add(len as u64)
.ok_or(SectorRangeError::Overflow)?;
let aligned_end = checked_align_up(end, sector_u64).ok_or(SectorRangeError::Overflow)?;
let aligned_len_u64 = aligned_end
.checked_sub(aligned_offset)
.ok_or(SectorRangeError::Overflow)?;
let aligned_len = usize::try_from(aligned_len_u64).map_err(|_| SectorRangeError::Overflow)?;
Ok(Self {
aligned_offset,
aligned_len,
internal_offset,
})
}
#[inline(always)]
pub const fn sector_count(&self, sector_size: usize) -> usize {
if self.aligned_len == 0 || sector_size == 0 {
0
} else {
self.aligned_len / sector_size
}
}
#[inline(always)]
pub const fn sub_range(&self, len: usize) -> Range<usize> {
self.internal_offset..self.internal_offset.saturating_add(len)
}
}