use polars_utils::slice::load_padded_le_u64;
use super::get_bit_unchecked;
use crate::trusted_len::TrustedLen;
#[derive(Debug, Clone)]
pub struct BitmapIter<'a> {
bytes: &'a [u8],
word: u64,
word_len: usize,
rest_len: usize,
}
impl<'a> BitmapIter<'a> {
pub fn new(bytes: &'a [u8], offset: usize, len: usize) -> Self {
if len == 0 {
return Self {
bytes,
word: 0,
word_len: 0,
rest_len: 0,
};
}
assert!(bytes.len() * 8 >= offset + len);
let first_byte_idx = offset / 8;
let bytes = &bytes[first_byte_idx..];
let offset = offset % 8;
let word = load_padded_le_u64(bytes) >> offset;
let mod8 = bytes.len() % 8;
let first_word_bytes = if mod8 > 0 { mod8 } else { 8 };
let bytes = &bytes[first_word_bytes..];
let word_len = (first_word_bytes * 8 - offset).min(len);
let rest_len = len - word_len;
Self {
bytes,
word,
word_len,
rest_len,
}
}
}
impl<'a> Iterator for BitmapIter<'a> {
type Item = bool;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.word_len != 0 {
let ret = self.word & 1 != 0;
self.word >>= 1;
self.word_len -= 1;
return Some(ret);
}
if self.rest_len != 0 {
self.word_len = self.rest_len.min(64);
self.rest_len -= self.word_len;
unsafe {
let chunk = self.bytes.get_unchecked(..8).try_into().unwrap();
self.word = u64::from_le_bytes(chunk);
self.bytes = self.bytes.get_unchecked(8..);
}
let ret = self.word & 1 != 0;
self.word >>= 1;
self.word_len -= 1;
return Some(ret);
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.word_len + self.rest_len;
(exact, Some(exact))
}
}
impl<'a> DoubleEndedIterator for BitmapIter<'a> {
#[inline]
fn next_back(&mut self) -> Option<bool> {
if self.rest_len > 0 {
self.rest_len -= 1;
Some(unsafe { get_bit_unchecked(self.bytes, self.rest_len) })
} else if self.word_len > 0 {
self.word_len -= 1;
Some(self.word & (1 << self.word_len) != 0)
} else {
None
}
}
}
unsafe impl TrustedLen for BitmapIter<'_> {}
impl ExactSizeIterator for BitmapIter<'_> {}