use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Index;
use std::sync::Arc;
use crate::enums::error::MinarrowError;
use crate::enums::shape_dim::ShapeDim;
use crate::traits::concatenate::Concatenate;
use crate::traits::print::MAX_PREVIEW;
use crate::traits::shape::Shape;
use crate::{Bitmask, BitmaskVT};
#[derive(Clone, PartialEq)]
pub struct BitmaskV {
pub bitmask: Arc<Bitmask>,
pub offset: usize,
len: usize,
}
impl BitmaskV {
#[inline]
pub fn new(bitmask: Bitmask, offset: usize, len: usize) -> Self {
assert!(
offset + len <= bitmask.len(),
"BitmaskView: out of bounds (offset + len = {}, bitmask.len = {})",
offset + len,
bitmask.len()
);
Self {
bitmask: bitmask.into(),
offset,
len,
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn get(&self, i: usize) -> bool {
assert!(
i < self.len,
"BitmaskView: index {i} out of bounds for window len {}",
self.len
);
self.bitmask.get(self.offset + i)
}
#[inline]
pub fn as_bytes_window(&self) -> (&[u8], usize, usize) {
self.bitmask.slice(self.offset, self.len)
}
#[inline]
pub fn to_bitmask(&self) -> Bitmask {
self.bitmask.slice_clone(self.offset, self.len)
}
pub fn iter_set(&self) -> impl Iterator<Item = usize> + '_ {
(0..self.len).filter(move |&i| self.get(i))
}
pub fn iter_cleared(&self) -> impl Iterator<Item = usize> + '_ {
(0..self.len).filter(move |&i| !self.get(i))
}
pub fn count_ones(&self) -> usize {
self.iter_set().count()
}
pub fn count_zeros(&self) -> usize {
self.iter_cleared().count()
}
#[inline]
pub fn all_set(&self) -> bool {
self.count_ones() == self.len
}
#[inline]
pub fn all_unset(&self) -> bool {
self.count_zeros() == self.len
}
#[inline]
pub fn has_cleared(&self) -> bool {
!self.all_set()
}
#[inline]
pub fn any_set(&self) -> bool {
self.count_ones() > 0
}
#[inline]
pub fn slice(&self, offset: usize, len: usize) -> Self {
assert!(
offset + len <= self.len,
"BitmaskView::slice: out of bounds"
);
Self {
bitmask: self.bitmask.clone(),
offset: self.offset + offset,
len,
}
}
#[inline]
pub fn end(&self) -> usize {
self.offset + self.len
}
#[inline]
pub fn as_tuple(&self) -> BitmaskVT<'_> {
(&self.bitmask, self.offset, self.len)
}
}
impl Index<usize> for BitmaskV {
type Output = bool;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
static TRUE_CONST: bool = true;
static FALSE_CONST: bool = false;
if self.get(index) {
&TRUE_CONST
} else {
&FALSE_CONST
}
}
}
impl Debug for BitmaskV {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("BitmaskView")
.field("offset", &self.offset)
.field("len", &self.len)
.field("set_count", &self.count_ones())
.field("unset_count", &self.count_zeros())
.finish()
}
}
impl Display for BitmaskV {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let len = self.len;
let offset = self.offset;
let set = self.count_ones();
let unset = len - set;
writeln!(
f,
"BitmaskView [{} bits] (offset: {}, set: {}, unset: {})",
len, offset, set, unset
)?;
let limit = len.min(MAX_PREVIEW);
write!(f, " ")?;
for i in 0..limit {
let symbol = if self.get(i) { '1' } else { '.' };
write!(f, "{symbol}")?;
}
if len > MAX_PREVIEW {
write!(f, "... ({} more bits)", len - MAX_PREVIEW)?;
}
writeln!(f)?;
Ok(())
}
}
impl Shape for BitmaskV {
fn shape(&self) -> ShapeDim {
ShapeDim::Rank1(self.len())
}
}
impl Concatenate for BitmaskV {
fn concat(self, other: Self) -> Result<Self, MinarrowError> {
let self_bitmask = self.to_bitmask();
let other_bitmask = other.to_bitmask();
let concatenated = self_bitmask.concat(other_bitmask)?;
let len = concatenated.len();
Ok(BitmaskV::new(concatenated, 0, len))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Bitmask;
#[test]
fn test_bitmask_view_basic_access() {
let bits = [true, false, true, false, true, false, true, false];
let mask = Bitmask::from_bools(&bits);
let view = BitmaskV::new(mask, 0, 8);
assert_eq!(view.len(), 8);
for i in 0..8 {
assert_eq!(view.get(i), bits[i]);
assert_eq!(view[i], bits[i]);
}
assert_eq!(view.count_ones(), 4);
assert_eq!(view.count_zeros(), 4);
assert!(!view.is_empty());
assert!(!view.all_set());
assert!(!view.all_unset());
assert!(view.any_set());
assert!(view.has_cleared());
assert_eq!(view.end(), 8);
let set_indices: Vec<_> = view.iter_set().collect();
assert_eq!(set_indices, vec![0, 2, 4, 6]);
let unset_indices: Vec<_> = view.iter_cleared().collect();
assert_eq!(unset_indices, vec![1, 3, 5, 7]);
}
#[test]
fn test_bitmask_view_offset_and_window() {
let bits = [true, true, false, false, true, true, false, false];
let mask = Bitmask::from_bools(&bits);
let view = BitmaskV::new(mask, 2, 4);
assert_eq!(view.len(), 4);
assert_eq!(
(0..4).map(|i| view.get(i)).collect::<Vec<_>>(),
vec![false, false, true, true]
);
assert_eq!(view.count_ones(), 2);
assert_eq!(view.count_zeros(), 2);
let (bytes, bit_offset, len) = view.as_bytes_window();
assert!(len == 4 && bit_offset < 8 && !bytes.is_empty());
}
#[test]
fn test_bitmask_view_slice_and_to_bitmask() {
let bits = [
true, true, true, false, false, false, true, false, true, true,
];
let mask = Bitmask::from_bools(&bits);
let view = BitmaskV::new(mask, 2, 6); assert_eq!(view.len(), 6);
assert_eq!(view.get(0), true);
assert_eq!(view.get(1), false);
assert_eq!(view.get(5), false);
let subview = view.slice(2, 3); assert_eq!(subview.len(), 3);
assert_eq!(subview.get(0), false);
assert_eq!(subview.get(1), false);
assert_eq!(subview.get(2), true);
let new_mask = subview.to_bitmask();
let expected = Bitmask::from_bools(&[false, false, true]);
assert_eq!(new_mask, expected);
}
#[test]
fn test_bitmask_view_empty_and_single_bit() {
let mask = Bitmask::from_bools(&[]);
let view = BitmaskV::new(mask, 0, 0);
assert_eq!(view.len(), 0);
assert!(view.is_empty());
assert!(view.all_set()); assert!(view.all_unset());
let mask2 = Bitmask::from_bools(&[true]);
let view2 = BitmaskV::new(mask2, 0, 1);
assert_eq!(view2.len(), 1);
assert!(!view2.is_empty());
assert_eq!(view2.get(0), true);
assert!(view2.all_set());
assert!(!view2.all_unset());
assert!(!view2.has_cleared());
assert!(view2.any_set());
}
#[test]
#[should_panic(expected = "BitmaskView: out of bounds")]
fn test_bitmask_view_out_of_bounds() {
let mask = Bitmask::from_bools(&[true, false, true]);
let _ = BitmaskV::new(mask, 2, 2); }
#[test]
#[should_panic(expected = "BitmaskView: index 3 out of bounds")]
fn test_bitmask_view_get_oob() {
let mask = Bitmask::from_bools(&[true, false, true, true]);
let view = BitmaskV::new(mask, 1, 2);
let _ = view.get(3); }
#[test]
fn test_bitmask_view_debug() {
let bits = [true, false, true, false];
let mask = Bitmask::from_bools(&bits);
let view = BitmaskV::new(mask, 0, 4);
let dbg = format!("{:?}", view);
assert!(dbg.contains("BitmaskView"));
assert!(dbg.contains("offset"));
assert!(dbg.contains("set_count"));
}
}