use crate::{
access::BitAccess,
cursor::{
Cursor,
Local,
},
domain::*,
indices::Indexable,
pointer::BitPtr,
store::{
BitStore,
Word,
},
};
use core::marker::PhantomData;
use either::Either;
#[repr(transparent)]
pub struct BitSlice<C = Local, T = Word>
where C: Cursor, T: BitStore {
_kind: PhantomData<C>,
_type: PhantomData<T>,
_elts: [()],
}
impl<C, T> BitSlice<C, T>
where C: Cursor, T: BitStore {
pub fn empty<'a>() -> &'a Self {
BitPtr::empty().into_bitslice()
}
pub fn empty_mut<'a>() -> &'a mut Self {
BitPtr::empty().into_bitslice_mut()
}
pub fn from_element(elt: &T) -> &Self {
unsafe {
BitPtr::new_unchecked(elt, 0u8.idx(), T::BITS as usize)
}.into_bitslice()
}
pub fn from_element_mut(elt: &mut T) -> &mut Self {
unsafe {
BitPtr::new_unchecked(elt, 0u8.idx(), T::BITS as usize)
}.into_bitslice_mut()
}
pub fn from_slice(slice: &[T]) -> &Self {
let len = slice.len();
assert!(
len <= BitPtr::<T>::MAX_ELTS,
"BitSlice cannot address {} elements",
len,
);
let bits = len.checked_mul(T::BITS as usize)
.expect("Bit length out of range");
BitPtr::new(slice.as_ptr(), 0u8.idx(), bits).into_bitslice()
}
pub fn from_slice_mut(slice: &mut [T]) -> &mut Self {
Self::from_slice(slice).bitptr().into_bitslice_mut()
}
pub fn set(&mut self, index: usize, value: bool) {
let len = self.len();
assert!(index < len, "Index out of range: {} >= {}", index, len);
unsafe { self.set_unchecked(index, value) };
}
pub unsafe fn set_unchecked(&mut self, index: usize, value: bool) {
let bitptr = self.bitptr();
let (elt, bit) = bitptr.head().offset(index as isize);
let data_ptr = bitptr.pointer().a();
(&*data_ptr.offset(elt)).set::<C>(bit, value);
}
pub fn at(&mut self, index: usize) -> BitMut<C, T> {
let len = self.len();
assert!(index < len, "Index {} out of bounds: {}", index, len);
unsafe { self.at_unchecked(index) }
}
pub unsafe fn at_unchecked(&mut self, index: usize) -> BitMut<C, T> {
BitMut {
data: *self.get_unchecked(index),
slot: self.get_unchecked_mut(index ..= index),
}
}
pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&Self, &Self) {
match mid {
0 => (BitSlice::empty(), self),
n if n == self.len() => (self, BitSlice::empty()),
_ => (self.get_unchecked(.. mid), self.get_unchecked(mid ..)),
}
}
pub unsafe fn split_at_mut_unchecked(
&mut self,
mid: usize,
) -> (&mut Self, &mut Self) {
let (head, tail) = self.split_at_unchecked(mid);
(head.bitptr().into_bitslice_mut(), tail.bitptr().into_bitslice_mut())
}
pub fn all(&self) -> bool {
match self.bitptr().domain().splat() {
Either::Right((h, e, t)) => {
let elt = e.load();
(*h .. *t).all(|n| elt.get::<C>(n.idx()))
},
Either::Left((h, b, t)) => {
let mut out = true;
if let Some((h, head)) = h {
let elt = head.load();
out &= (*h .. T::BITS).all(|n| elt.get::<C>(n.idx()));
}
if let Some(body) = b {
out &= body.iter().all(|e| e.load() == T::TRUE);
}
if let Some((tail, t)) = t {
let elt = tail.load();
out &= (0 .. *t).all(|n| elt.get::<C>(n.idx()));
}
out
},
}
}
pub fn any(&self) -> bool {
match self.bitptr().domain().splat() {
Either::Right((h, e, t)) => {
let elt = e.load();
(*h .. *t).any(|n| elt.get::<C>(n.idx()))
},
Either::Left((h, b, t)) => {
let mut out = false;
if let Some((h, head)) = h {
let elt = head.load();
out |= (*h .. T::BITS).any(|n| elt.get::<C>(n.idx()));
}
if let Some(body) = b {
out |= body.iter().any(|elt| elt.load() != T::FALSE);
}
if let Some((tail, t)) = t {
let elt = tail.load();
out |= (0 .. *t).any(|n| elt.get::<C>(n.idx()));
}
out
},
}
}
pub fn not_all(&self) -> bool {
!self.all()
}
pub fn not_any(&self) -> bool {
!self.any()
}
pub fn some(&self) -> bool {
self.any() && self.not_all()
}
pub fn count_ones(&self) -> usize {
match self.bitptr().domain().splat() {
Either::Right((h, e, t)) => {
let elt = e.load();
(*h .. *t).filter(|n| elt.get::<C>(n.idx())).count()
},
Either::Left((h, b, t)) => {
let mut out = 0usize;
if let Some((h, head)) = h {
let elt = head.load();
out += (*h .. T::BITS)
.filter(|n| elt.get::<C>(n.idx()))
.count();
}
if let Some(body) = b {
out += body.iter()
.map(BitAccess::load)
.map(T::count_ones)
.sum::<usize>();
}
if let Some((tail, t)) = t {
let elt = tail.load();
out += (0 .. *t)
.filter(|n| elt.get::<C>(n.idx()))
.count();
}
out
},
}
}
pub fn count_zeros(&self) -> usize {
self.len() - self.count_ones()
}
pub fn set_all(&mut self, value: bool) {
match self.bitptr().domain().splat() {
Either::Right((h, e, t)) => {
for n in *h .. *t {
e.set::<C>(n.idx(), value);
}
},
Either::Left((h, b, t)) => {
if let Some((h, head)) = h {
for n in *h .. T::BITS {
head.set::<C>(n.idx(), value);
}
}
if let Some(body) = b {
for elt in body {
elt.store(if value { T::TRUE } else { T::FALSE });
}
}
if let Some((tail, t)) = t {
for n in 0 .. *t {
tail.set::<C>(n.idx(), value);
}
}
},
}
}
pub fn for_each<F>(&mut self, func: F)
where F: Fn(usize, bool) -> bool {
for idx in 0 .. self.len() {
let tmp = unsafe { *self.get_unchecked(idx) };
let new = func(idx, tmp);
unsafe { self.set_unchecked(idx, new); }
}
}
pub fn add_assign_reverse<I>(&mut self, addend: I) -> bool
where I: IntoIterator<Item=bool> {
let mut c = false;
let len = self.len();
let zero = core::iter::repeat(false);
for (i, b) in addend.into_iter().chain(zero).enumerate().take(len) {
let a = unsafe { *self.get_unchecked(i) };
let (y, z) = crate::rca1(a, b, c);
unsafe { self.set_unchecked(i, y); }
c = z;
}
c
}
pub fn as_slice(&self) -> &[T] {
&* unsafe { BitAccess::as_slice_mut(match self.bitptr().domain() {
| BitDomain::Empty
| BitDomain::Minor(_, _, _) => &[],
| BitDomain::PartialHead(_, _, body)
| BitDomain::PartialTail(body, _, _)
| BitDomain::Major(_, _, body, _, _)
| BitDomain::Spanning(body) => body,
}) }
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { BitAccess::as_slice_mut(match self.bitptr().domain() {
| BitDomain::Empty
| BitDomain::Minor(_, _, _) => &[],
| BitDomain::PartialHead(_, _, body)
| BitDomain::PartialTail(body, _, _)
| BitDomain::Major(_, _, body, _, _)
| BitDomain::Spanning(body) => body,
}) }
}
pub fn as_total_slice(&self) -> &[T::Access] {
self.bitptr().as_access_slice()
}
pub(crate) fn bitptr(&self) -> BitPtr<T> {
BitPtr::from_bitslice(self)
}
unsafe fn copy_unchecked(&mut self, from: usize, to: usize) {
self.set_unchecked(to, *self.get_unchecked(from));
}
}
mod api;
mod guard;
pub(crate) mod iter;
mod ops;
mod traits;
pub use self::api::*;
pub use self::guard::*;
pub use self::iter::*;
#[cfg(test)]
mod tests;