use crate::{
access::BitAccess,
indices::BitIdx,
order::BitOrder,
};
use core::{
convert::TryInto,
fmt::{
Binary,
Debug,
Display,
LowerHex,
UpperHex,
},
mem::size_of,
ops::{
BitAnd,
BitAndAssign,
BitOr,
BitOrAssign,
Not,
Shl,
ShlAssign,
Shr,
ShrAssign,
},
};
use radium::marker::BitOps;
#[cfg(feature = "atomic")]
use core::sync::atomic;
#[cfg(not(feature = "atomic"))]
use core::cell::Cell;
pub trait BitStore:
Sealed
+ Binary
+ BitAnd<Self, Output = Self>
+ BitAndAssign<Self>
+ BitOr<Self, Output = Self>
+ BitOrAssign<Self>
+ Copy
+ Debug
+ Display
+ Eq
+ From<u8>
+ TryInto<usize>
+ LowerHex
+ Not<Output = Self>
+ Send
+ Shl<u8, Output = Self>
+ ShlAssign<u8>
+ Shr<u8, Output = Self>
+ ShrAssign<u8>
+ Sized
+ Sync
+ UpperHex
+ BitOps
{
const BITS: u8 = size_of::<Self>() as u8 * 8;
const INDX: u8 = Self::BITS.trailing_zeros() as u8;
const MASK: u8 = Self::BITS - 1;
const FALSE: Self;
const TRUE: Self;
const TYPENAME: &'static str;
type Access: BitAccess<Self>;
fn get<O>(&self, place: BitIdx<Self>) -> bool
where O: BitOrder {
*self & *O::mask(place) != Self::FALSE
}
fn set<O>(&mut self, place: BitIdx<Self>, value: bool)
where O: BitOrder {
let mask = *O::mask(place);
if value {
*self |= mask;
}
else {
*self &= !mask;
}
}
#[inline(always)]
fn count_ones(self) -> usize {
let extended = self.try_into()
.unwrap_or_else(|_| unreachable!("This conversion is infallible"));
usize::count_ones(extended) as usize
}
#[inline(always)]
fn count_zeros(self) -> usize {
<Self as BitStore>::count_ones(!self)
}
}
#[doc(hidden)]
pub const fn elts<T>(bits: usize) -> usize {
let width: usize = size_of::<T>() * 8;
bits / width + (bits % width != 0) as usize
}
macro_rules! bitstore {
($($t:ty => $bits:literal , $atom:ty ;)*) => { $(
impl BitStore for $t {
const TYPENAME: &'static str = stringify!($t);
const FALSE: Self = 0;
const TRUE: Self = !0;
#[cfg(feature = "atomic")]
type Access = $atom;
#[cfg(not(feature = "atomic"))]
type Access = Cell<Self>;
#[inline(always)]
fn count_ones(self) -> usize {
Self::count_ones(self) as usize
}
}
)* };
}
bitstore! {
u8 => 1, atomic::AtomicU8;
u16 => 2, atomic::AtomicU16;
u32 => 4, atomic::AtomicU32;
}
#[cfg(target_pointer_width = "32")]
bitstore! {
usize => 4, atomic::AtomicUsize;
}
#[cfg(target_pointer_width = "64")]
bitstore! {
u64 => 8, atomic::AtomicU64;
usize => 8, atomic::AtomicUsize;
}
#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
compile_fail!("This architecture is currently not supported. File an issue at https://github.com/myrrlyn/bitvec");
#[doc(hidden)]
pub trait Sealed {}
macro_rules! seal {
($($t:ty),*) => { $(
impl Sealed for $t {}
)* };
}
seal!(u8, u16, u32, usize);
#[cfg(target_pointer_width = "64")]
seal!(u64);