use std::{
marker::PhantomData,
ops::{BitAndAssign, BitOrAssign, BitXorAssign},
ptr::NonNull,
};
use crate::{
BitRead, Iter,
traits::{BitWord, BitWrite},
};
pub struct BitSpan<'a, T: BitWord> {
ptr: NonNull<T>,
offset: usize,
len: usize,
_marker: PhantomData<&'a T>,
}
pub struct BitSpanMut<'a, T: BitWord> {
ptr: NonNull<T>,
offset: usize,
len: usize,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T: BitWord> BitSpan<'a, T> {
pub(crate) fn new(ptr: NonNull<T>, offset: usize, len: usize) -> Self {
Self {
ptr,
offset,
len,
_marker: PhantomData,
}
}
pub fn from_raw_parts(ptr: *const T, offset: usize, len: usize) -> Self {
Self {
ptr: NonNull::new(ptr as *mut T).unwrap_or(NonNull::dangling()),
offset,
len,
_marker: PhantomData,
}
}
}
pub struct BitSpanIter<'a, T: BitWord> {
offset: usize,
iter: Iter<'a, T>,
}
impl<'a, T: BitWord> Iterator for BitSpanIter<'a, T> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|i| self.offset + i)
}
}
impl<'a, T: BitWord> BitSpan<'a, T> {
#[inline(always)]
fn ptr_and_mask(&self, idx: usize) -> (*const T, T) {
let bit_idx = self.offset + idx;
let word_idx = bit_idx / usize::BITS as usize;
let bit_in_word = bit_idx % usize::BITS as usize;
let ptr = unsafe { self.ptr.as_ptr().add(word_idx) };
let mask = T::from(1) << bit_in_word;
(ptr, mask)
}
}
impl<'a, T: BitWord> BitRead for BitSpan<'a, T> {
type Iter<'b>
= BitSpanIter<'b, T>
where
Self: 'b;
fn len(&self) -> usize {
self.len
}
fn is_empty(&self) -> bool {
self.len == 0 || self.count_ones() == 0
}
fn test(&self, idx: usize) -> bool {
assert!(idx < self.len, "index out of bounds");
let (ptr, mask) = self.ptr_and_mask(idx);
unsafe { (*ptr & mask) != T::from(0) }
}
fn count_ones(&self) -> usize {
let mut count = 0;
for i in 0..self.len {
if self.test(i) {
count += 1;
}
}
count
}
fn all(&self) -> bool {
self.len > 0 && self.count_ones() == self.len
}
fn any(&self) -> bool {
self.count_ones() > 0
}
fn iter(&self) -> Self::Iter<'_> {
BitSpanIter {
offset: self.offset,
iter: Iter::from_raw_parts(self.ptr.as_ptr(), self.len),
}
}
}
impl<'a, T: BitWord> BitSpanMut<'a, T> {
pub(crate) fn new(ptr: NonNull<T>, offset: usize, len: usize) -> Self {
Self {
ptr,
offset,
len,
_marker: PhantomData,
}
}
pub fn from_raw_parts_mut(ptr: *mut T, offset: usize, len: usize) -> Self {
Self {
ptr: NonNull::new(ptr).unwrap_or(NonNull::dangling()),
offset,
len,
_marker: PhantomData,
}
}
#[inline(always)]
fn ptr_and_mask(&self, idx: usize) -> (*mut T, T) {
let bit_idx = self.offset + idx;
let word_idx = bit_idx / usize::BITS as usize;
let bit_in_word = bit_idx % usize::BITS as usize;
let ptr = unsafe { self.ptr.as_ptr().add(word_idx) };
let mask = T::from(1) << bit_in_word;
(ptr, mask)
}
}
impl<'a, T: BitWord> BitRead for BitSpanMut<'a, T> {
type Iter<'b>
= BitSpanIter<'b, T>
where
Self: 'b;
fn len(&self) -> usize {
self.len
}
fn is_empty(&self) -> bool {
self.len == 0 || self.count_ones() == 0
}
fn test(&self, idx: usize) -> bool {
debug_assert!(idx < self.len, "index out of bounds");
let (ptr, mask) = self.ptr_and_mask(idx);
unsafe { (*ptr & mask) != T::from(0) }
}
fn count_ones(&self) -> usize {
let mut count = 0;
for i in 0..self.len {
if self.test(i) {
count += 1;
}
}
count
}
fn all(&self) -> bool {
self.len > 0 && self.count_ones() == self.len
}
fn any(&self) -> bool {
self.count_ones() > 0
}
fn iter(&self) -> Self::Iter<'_> {
BitSpanIter {
offset: self.offset,
iter: Iter::from_raw_parts(self.ptr.as_ptr(), self.len),
}
}
}
impl<'a, T: BitWord> BitWrite for BitSpanMut<'a, T> {
fn set(&mut self, idx: usize) {
debug_assert!(idx < self.len, "index out of bounds");
let (ptr, mask) = self.ptr_and_mask(idx);
unsafe {
*ptr |= mask;
}
}
fn reset(&mut self, idx: usize) {
debug_assert!(idx < self.len, "index out of bounds");
let (ptr, mask) = self.ptr_and_mask(idx);
unsafe {
*ptr &= !mask;
}
}
fn flip(&mut self, idx: usize) {
assert!(idx < self.len);
let (ptr, mask) = self.ptr_and_mask(idx);
unsafe {
*ptr ^= mask;
}
}
fn test_and_set(&mut self, idx: usize) -> bool {
debug_assert!(idx < self.len, "index out of bounds");
let (ptr, mask) = self.ptr_and_mask(idx);
unsafe {
let old = *ptr & mask;
*ptr |= mask;
old != T::from(0)
}
}
fn fill(&mut self) {
if self.len == 0 {
return;
}
let start_bit = self.offset;
let end_bit = self.offset + self.len;
let start_word = start_bit / usize::BITS as usize;
let end_word = (end_bit + usize::BITS as usize - 1) / usize::BITS as usize;
let first_bit = start_bit % usize::BITS as usize;
let last_bit = (end_bit - 1) % usize::BITS as usize;
for word_idx in start_word..end_word {
let ptr = unsafe { self.ptr.as_ptr().add(word_idx) as *mut usize };
let mut mask = usize::MAX;
if word_idx == start_word {
mask &= usize::MAX << first_bit;
}
if word_idx == end_word - 1 {
mask &= usize::MAX >> (usize::BITS as usize - 1 - last_bit);
}
unsafe {
*ptr |= mask;
}
}
}
fn clear(&mut self) {
if self.len == 0 {
return;
}
let start_bit = self.offset;
let end_bit = self.offset + self.len;
let start_word = start_bit / usize::BITS as usize;
let end_word = (end_bit + usize::BITS as usize - 1) / usize::BITS as usize;
let first_bit = start_bit % usize::BITS as usize;
let last_bit = (end_bit - 1) % usize::BITS as usize;
for word_idx in start_word..end_word {
let ptr = unsafe { self.ptr.as_ptr().add(word_idx) as *mut usize };
let mut mask = usize::MAX;
if word_idx == start_word {
mask &= usize::MAX << first_bit;
}
if word_idx == end_word - 1 {
mask &= usize::MAX >> (usize::BITS as usize - 1 - last_bit);
}
unsafe {
*ptr &= !mask;
}
}
}
}
impl<'a, 'b, T: BitWord> BitAndAssign<&'b BitSpan<'b, T>> for BitSpanMut<'a, T> {
fn bitand_assign(&mut self, rhs: &'b BitSpan<'b, T>) {
for index in self.iter().collect::<Vec<_>>() {
if !rhs.test(index) {
self.reset(index);
}
}
}
}
impl<'a, 'b, T: BitWord> BitOrAssign<&'b BitSpan<'b, T>> for BitSpanMut<'a, T> {
fn bitor_assign(&mut self, rhs: &'b BitSpan<'b, T>) {
for i in rhs.iter() {
self.set(i);
}
}
}
impl<'a, 'b, T: BitWord> BitXorAssign<&'b BitSpan<'b, T>> for BitSpanMut<'a, T> {
fn bitxor_assign(&mut self, rhs: &'b BitSpan<'b, T>) {
for index in self.iter().collect::<Vec<_>>() {
if rhs.test(index) {
self.reset(index);
}
}
for index in rhs.iter() {
if self.test(index) {
self.reset(index);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitspan_from_raw_parts_and_test() {
let data = [0b10101010usize, 0b01010101usize];
let span = BitSpan::from_raw_parts(data.as_ptr(), 0, 128);
assert_eq!(span.len(), 128);
assert!(!span.test(0));
assert!(span.test(1));
assert!(!span.test(2));
assert!(span.test(3));
}
#[test]
fn test_bitspan_iter() {
let data = [0b1011usize];
let span = BitSpan::from_raw_parts(data.as_ptr(), 0, 4);
let bits: Vec<_> = span.iter().collect();
assert_eq!(bits, vec![0, 1, 3]);
}
#[test]
fn test_bitspan_count_ones_and_any_all() {
let data = [0b1111usize];
let span = BitSpan::from_raw_parts(data.as_ptr(), 0, 4);
assert_eq!(span.count_ones(), 4);
assert!(span.all());
assert!(span.any());
let data = [0usize];
let span = BitSpan::from_raw_parts(data.as_ptr(), 0, 4);
assert_eq!(span.count_ones(), 0);
assert!(!span.all());
assert!(!span.any());
}
#[test]
fn test_bitspanmut_set_reset_test_and_set() {
let mut data = [0usize];
let mut span = BitSpanMut::from_raw_parts_mut(data.as_mut_ptr(), 0, 4);
for i in 0..4 {
assert!(!span.test(i));
span.set(i);
assert!(span.test(i));
assert!(span.test_and_set(i)); span.reset(i);
assert!(!span.test(i));
assert!(!span.test_and_set(i)); }
}
#[test]
fn test_bitspanmut_fill_and_clear() {
let mut data = [0usize; 2];
let mut span =
BitSpanMut::from_raw_parts_mut(data.as_mut_ptr(), 0, 2 * usize::BITS as usize);
span.fill();
for i in 0..span.len() {
assert!(span.test(i));
}
span.clear();
for i in 0..span.len() {
assert!(!span.test(i));
}
}
#[test]
fn test_bitspanmut_partial_fill_and_clear() {
let mut data = [0usize; 2];
let mut span = BitSpanMut::from_raw_parts_mut(data.as_mut_ptr(), 5, 10);
span.fill();
for i in 0..span.len() {
assert!(span.test(i));
}
for i in 0..5 {
assert!(!unsafe { (*data.as_ptr() & (1 << i)) != 0 });
}
span.clear();
for i in 0..span.len() {
assert!(!span.test(i));
}
}
#[test]
fn test_empty_bitspan() {
let data = [0usize];
let span = BitSpan::from_raw_parts(data.as_ptr(), 0, 0);
assert_eq!(span.len(), 0);
assert!(span.is_empty());
assert_eq!(span.count_ones(), 0);
assert!(!span.any());
assert!(!span.all());
assert_eq!(span.iter().count(), 0);
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_bitspan_test_out_of_bounds() {
let data = [0usize];
let span = BitSpan::from_raw_parts(data.as_ptr(), 0, 1);
span.test(1);
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_bitspanmut_set_out_of_bounds() {
let mut data = [0usize];
let mut span = BitSpanMut::from_raw_parts_mut(data.as_mut_ptr(), 0, 1);
span.set(1);
}
}