use crate::{BitError, IntoBitRange};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct Bits<T>(pub T);
impl<T: core::fmt::Debug> core::fmt::Debug for Bits<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Bits({:?})", self.0)
}
}
impl<T> Bits<T> {
#[inline] pub const fn new(value: T) -> Self { Self(value) }
}
impl<T: Copy> Bits<T> {
#[inline] pub const fn get(self) -> T { self.0 }
}
macro_rules! impl_bits {
($ty:ty) => {
impl Bits<$ty> {
pub const BITS: u32 = <$ty>::BITS;
#[inline] pub const fn has_bit(self, index: u32) -> Result<bool, BitError> {
if index < Self::BITS { Ok((self.0 & ((1 as $ty) << index)) != 0) } else { Err(BitError::IndexOutOfRange) }
}
#[inline] pub const fn set_bit(self, index: u32) -> Result<Self, BitError> {
if index < Self::BITS { Ok(Self(self.0 | ((1 as $ty) << index))) } else { Err(BitError::IndexOutOfRange) }
}
#[inline] pub const fn clear_bit(self, index: u32) -> Result<Self, BitError> {
if index < Self::BITS { Ok(Self(self.0 & !((1 as $ty) << index))) } else { Err(BitError::IndexOutOfRange) }
}
#[inline] pub const fn toggle_bit(self, index: u32) -> Result<Self, BitError> {
if index < Self::BITS { Ok(Self(self.0 ^ ((1 as $ty) << index))) } else { Err(BitError::IndexOutOfRange) }
}
#[inline] pub const fn has_bit_wrapping(self, index: u32) -> bool { (self.0 & ((1 as $ty) << (index % Self::BITS))) != 0 }
#[inline] pub const fn set_bit_wrapping(self, index: u32) -> Self { Self(self.0 | ((1 as $ty) << (index % Self::BITS))) }
#[inline] pub const fn clear_bit_wrapping(self, index: u32) -> Self { Self(self.0 & !((1 as $ty) << (index % Self::BITS))) }
#[inline] pub const fn toggle_bit_wrapping(self, index: u32) -> Self { Self(self.0 ^ ((1 as $ty) << (index % Self::BITS))) }
#[inline] pub const fn isolate_lowest_set_bit(self) -> Self { Self(self.0 & self.0.wrapping_neg()) }
#[inline] pub const fn clear_lowest_set_bit(self) -> Self { Self(self.0 & self.0.wrapping_sub(1)) }
#[inline] pub const fn isolate_lowest_zero_bit(self) -> Self { let n = !self.0; Self(n & n.wrapping_neg()) }
#[inline] pub const fn set_lowest_zero_bit(self) -> Self { Self(self.0 | self.0.wrapping_add(1)) }
#[inline] pub const fn mask_through_lowest_set_bit(self) -> Self { Self(self.0 ^ self.0.wrapping_sub(1)) }
#[inline] pub const fn reverse_bits(self) -> Self { Self(self.0.reverse_bits()) }
#[inline] pub const fn zero_high_bits(self, n: u32) -> Result<Self, BitError> {
match Self::low_mask(n) { Ok(m) => Ok(Self(self.0 & m.0)), Err(e) => Err(e) }
}
#[inline] pub const fn count_ones(self) -> u32 { self.0.count_ones() }
#[inline] pub const fn count_zeros(self) -> u32 { self.0.count_zeros() }
#[inline] pub const fn leading_zeros(self) -> u32 { self.0.leading_zeros() }
#[inline] pub const fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() }
#[inline] pub const fn is_power_of_two(self) -> bool { self.0 != 0 && (self.0 & self.0.wrapping_sub(1)) == 0 }
#[inline]
pub const fn next_power_of_two(self) -> Result<Self, BitError> {
if self.0 == 0 { return Err(BitError::UnderflowFromZero); }
match <$ty>::checked_next_power_of_two(self.0) { Some(p) => Ok(Self(p)), None => Err(BitError::Overflow) }
}
#[inline]
pub const fn previous_power_of_two(self) -> Result<Self, BitError> {
if self.0 == 0 { Err(BitError::UnderflowFromZero) }
else { Ok(Self((1 as $ty) << (Self::BITS - 1 - self.0.leading_zeros()))) }
}
#[inline]
pub const fn low_mask(width: u32) -> Result<Self, BitError> {
if width > Self::BITS { Err(BitError::IndexOutOfRange) }
else if width == Self::BITS { Ok(Self(!(0 as $ty))) }
else { Ok(Self(((1 as $ty) << width) - 1)) }
}
#[inline]
pub const fn high_mask(width: u32) -> Result<Self, BitError> {
if width > Self::BITS { Err(BitError::IndexOutOfRange) }
else if width == 0 { Ok(Self(0 as $ty)) }
else if width == Self::BITS { Ok(Self(!(0 as $ty))) }
else { Ok(Self((!(0 as $ty)) << (Self::BITS - width))) }
}
#[inline]
pub fn range_mask(range: impl IntoBitRange) -> Result<Self, BitError> {
let (s, e) = range.into_bit_range();
Self::range_mask_indices(s, e)
}
#[inline]
pub const fn range_mask_indices(start: u32, end: u32) -> Result<Self, BitError> {
if end > Self::BITS || start > end { return Err(BitError::InvalidRange); }
if start == end { return Ok(Self(0 as $ty)); }
let w = end - start;
let low: $ty = if w == Self::BITS { !(0 as $ty) } else { ((1 as $ty) << w) - 1 };
Ok(Self(low << start))
}
#[inline]
pub fn extract(self, range: impl IntoBitRange) -> Result<Self, BitError> {
let (s, e) = range.into_bit_range();
self.extract_indices(s, e)
}
#[inline]
pub const fn extract_indices(self, start: u32, end: u32) -> Result<Self, BitError> {
if end > Self::BITS || start > end { return Err(BitError::InvalidRange); }
if start == end { return Ok(Self(0 as $ty)); }
let w = end - start;
let m: $ty = if w == Self::BITS { !(0 as $ty) } else { ((1 as $ty) << w) - 1 };
Ok(Self((self.0 >> start) & m))
}
#[inline]
pub fn insert(self, range: impl IntoBitRange, value: $ty) -> Result<Self, BitError> {
let (s, e) = range.into_bit_range();
self.insert_indices(s, e, value)
}
#[inline]
pub const fn insert_indices(self, start: u32, end: u32, value: $ty) -> Result<Self, BitError> {
if end > Self::BITS || start > end { return Err(BitError::InvalidRange); }
if start == end {
return if value != 0 { Err(BitError::FieldValueTooLarge) } else { Ok(self) };
}
let w = end - start;
let vm: $ty = if w == Self::BITS { !(0 as $ty) } else { ((1 as $ty) << w) - 1 };
if value & !vm != 0 { return Err(BitError::FieldValueTooLarge); }
let fm = vm << start;
Ok(Self((self.0 & !fm) | (value << start)))
}
#[inline]
pub fn replace(self, range: impl IntoBitRange, value: $ty) -> Result<Self, BitError> {
let (s, e) = range.into_bit_range();
self.replace_indices(s, e, value)
}
#[inline]
pub const fn replace_indices(self, start: u32, end: u32, value: $ty) -> Result<Self, BitError> {
if end > Self::BITS || start > end { return Err(BitError::InvalidRange); }
if start == end { return Ok(self); }
let w = end - start;
let vm: $ty = if w == Self::BITS { !(0 as $ty) } else { ((1 as $ty) << w) - 1 };
let fm = vm << start;
Ok(Self((self.0 & !fm) | ((value & vm) << start)))
}
#[inline] pub const fn set_bits(self) -> SetBits<$ty> { SetBits(self.0) }
#[inline] pub const fn set_bit_values(self) -> SetBitValues<$ty> { SetBitValues(self.0) }
#[inline] pub const fn zero_bits(self) -> ZeroBits<$ty> { ZeroBits(self.0) }
#[inline] pub const fn submasks(self) -> Submasks<$ty> { Submasks { mask: self.0, current: Some(self.0) } }
#[inline]
pub const fn proper_submasks(self) -> ProperSubmasks<$ty> {
ProperSubmasks { inner: Submasks { mask: self.0, current: Some(self.0) }, skipped: false }
}
}
impl From<$ty> for Bits<$ty> { #[inline] fn from(v: $ty) -> Self { Self(v) } }
impl From<Bits<$ty>> for $ty { #[inline] fn from(b: Bits<$ty>) -> Self { b.0 } }
impl core::ops::BitAnd for Bits<$ty> { type Output = Self; #[inline] fn bitand(self, r: Self) -> Self { Self(self.0 & r.0) } }
impl core::ops::BitOr for Bits<$ty> { type Output = Self; #[inline] fn bitor (self, r: Self) -> Self { Self(self.0 | r.0) } }
impl core::ops::BitXor for Bits<$ty> { type Output = Self; #[inline] fn bitxor(self, r: Self) -> Self { Self(self.0 ^ r.0) } }
impl core::ops::Not for Bits<$ty> { type Output = Self; #[inline] fn not (self) -> Self { Self(!self.0) } }
impl core::ops::BitAndAssign for Bits<$ty> { #[inline] fn bitand_assign(&mut self, r: Self) { self.0 &= r.0; } }
impl core::ops::BitOrAssign for Bits<$ty> { #[inline] fn bitor_assign (&mut self, r: Self) { self.0 |= r.0; } }
impl core::ops::BitXorAssign for Bits<$ty> { #[inline] fn bitxor_assign(&mut self, r: Self) { self.0 ^= r.0; } }
impl core::fmt::Binary for Bits<$ty> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::Binary ::fmt(&self.0, f) } }
impl core::fmt::LowerHex for Bits<$ty> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::LowerHex::fmt(&self.0, f) } }
impl core::fmt::UpperHex for Bits<$ty> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::UpperHex::fmt(&self.0, f) } }
};
}
impl_bits!(u8);
impl_bits!(u16);
impl_bits!(u32);
impl_bits!(u64);
impl_bits!(u128);
impl_bits!(usize);
use crate::accel;
impl Bits<u32> {
#[inline] pub fn gather(self, mask: Self) -> Self { Self(accel::pext_u32(self.0, mask.0)) }
#[inline] pub fn scatter(self, mask: Self) -> Self { Self(accel::pdep_u32(self.0, mask.0)) }
}
impl Bits<u64> {
#[inline] pub fn gather(self, mask: Self) -> Self { Self(accel::pext_u64(self.0, mask.0)) }
#[inline] pub fn scatter(self, mask: Self) -> Self { Self(accel::pdep_u64(self.0, mask.0)) }
}
#[derive(Clone, Debug)] pub struct SetBits<T>(T);
#[derive(Clone, Debug)] pub struct SetBitValues<T>(T);
#[derive(Clone, Debug)] pub struct ZeroBits<T>(T);
#[derive(Clone, Debug)] pub struct Submasks<T> { mask: T, current: Option<T> }
#[derive(Clone, Debug)] pub struct ProperSubmasks<T> { inner: Submasks<T>, skipped: bool }
macro_rules! impl_iters {
($ty:ty) => {
impl Iterator for SetBits<$ty> {
type Item = u32;
#[inline]
fn next(&mut self) -> Option<u32> {
if self.0 == 0 { None } else { let i = self.0.trailing_zeros(); self.0 &= self.0.wrapping_sub(1); Some(i) }
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { let c = self.0.count_ones() as usize; (c, Some(c)) }
#[inline]
fn for_each<F: FnMut(u32)>(self, mut f: F) {
let mut v = self.0;
while v != 0 { let i = v.trailing_zeros(); v &= v.wrapping_sub(1); f(i); }
}
}
impl ExactSizeIterator for SetBits<$ty> {}
impl core::iter::FusedIterator for SetBits<$ty> {}
impl Iterator for SetBitValues<$ty> {
type Item = $ty;
#[inline]
fn next(&mut self) -> Option<$ty> {
if self.0 == 0 { None } else { let b = self.0 & self.0.wrapping_neg(); self.0 ^= b; Some(b) }
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { let c = self.0.count_ones() as usize; (c, Some(c)) }
#[inline]
fn for_each<F: FnMut($ty)>(self, mut f: F) {
let mut v = self.0;
while v != 0 { let b = v & v.wrapping_neg(); v ^= b; f(b); }
}
}
impl ExactSizeIterator for SetBitValues<$ty> {}
impl core::iter::FusedIterator for SetBitValues<$ty> {}
impl Iterator for ZeroBits<$ty> {
type Item = u32;
#[inline]
fn next(&mut self) -> Option<u32> {
if self.0 == !(0 as $ty) { None }
else { let i = (!self.0).trailing_zeros(); self.0 |= (1 as $ty) << i; Some(i) }
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { let c = self.0.count_zeros() as usize; (c, Some(c)) }
#[inline]
fn for_each<F: FnMut(u32)>(self, mut f: F) {
let mut v = self.0;
while v != !(0 as $ty) { let i = (!v).trailing_zeros(); v |= (1 as $ty) << i; f(i); }
}
}
impl ExactSizeIterator for ZeroBits<$ty> {}
impl core::iter::FusedIterator for ZeroBits<$ty> {}
impl Iterator for Submasks<$ty> {
type Item = Bits<$ty>;
#[inline]
fn next(&mut self) -> Option<Bits<$ty>> {
let c = self.current?;
self.current = if c == 0 { None } else { Some(c.wrapping_sub(1) & self.mask) };
Some(Bits(c))
}
#[inline]
fn for_each<F: FnMut(Bits<$ty>)>(self, mut f: F) {
if let Some(start) = self.current {
let (mut c, mask) = (start, self.mask);
loop { f(Bits(c)); if c == 0 { break; } c = c.wrapping_sub(1) & mask; }
}
}
}
impl core::iter::FusedIterator for Submasks<$ty> {}
impl Iterator for ProperSubmasks<$ty> {
type Item = Bits<$ty>;
#[inline]
fn next(&mut self) -> Option<Bits<$ty>> {
if !self.skipped { self.skipped = true; let _ = self.inner.next(); }
self.inner.next()
}
#[inline]
fn for_each<F: FnMut(Bits<$ty>)>(mut self, f: F) {
if !self.skipped { let _ = self.inner.next(); }
self.inner.for_each(f);
}
}
impl core::iter::FusedIterator for ProperSubmasks<$ty> {}
};
}
impl_iters!(u8); impl_iters!(u16); impl_iters!(u32); impl_iters!(u64); impl_iters!(u128); impl_iters!(usize);