use crate::bitmap::Bitmap;
#[derive(Debug, Clone, PartialEq)]
enum State {
Nominal,
Finished,
}
#[derive(Debug, Clone)]
pub struct SlicesIterator<'a> {
values: std::slice::Iter<'a, u8>,
count: usize,
mask: u8,
max_len: usize,
current_byte: &'a u8,
state: State,
len: usize,
start: usize,
on_region: bool,
}
impl<'a> SlicesIterator<'a> {
pub fn new(values: &'a Bitmap) -> Self {
let (buffer, offset, _) = values.as_slice();
let mut iter = buffer.iter();
let (current_byte, state) = match iter.next() {
Some(b) => (b, State::Nominal),
None => (&0, State::Finished),
};
Self {
state,
count: values.len() - values.null_count(),
max_len: values.len(),
values: iter,
mask: 1u8.rotate_left(offset as u32),
current_byte,
len: 0,
start: 0,
on_region: false,
}
}
fn finish(&mut self) -> Option<(usize, usize)> {
self.state = State::Finished;
if self.on_region {
Some((self.start, self.len))
} else {
None
}
}
#[inline]
fn current_len(&self) -> usize {
self.start + self.len
}
#[inline]
pub fn slots(&self) -> usize {
self.count
}
}
impl<'a> Iterator for SlicesIterator<'a> {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.state == State::Finished {
return None;
}
if self.current_len() == self.max_len {
return self.finish();
}
if self.mask == 1 {
match (self.on_region, self.current_byte) {
(true, &255u8) => {
self.len = std::cmp::min(self.max_len - self.start, self.len + 8);
match self.values.next() {
Some(v) => self.current_byte = v,
None => return self.finish(),
};
continue;
}
(false, &0) => {
self.len = std::cmp::min(self.max_len - self.start, self.len + 8);
match self.values.next() {
Some(v) => self.current_byte = v,
None => return self.finish(),
};
continue;
}
_ => (), }
};
let value = (self.current_byte & self.mask) != 0;
self.mask = self.mask.rotate_left(1);
match (self.on_region, value) {
(true, true) => self.len += 1,
(false, false) => self.len += 1,
(true, false) => {
if self.mask == 1 {
match self.values.next() {
Some(v) => {
self.on_region = false;
let result = (self.start, self.len);
self.start += self.len;
self.len = 1;
self.current_byte = v;
return Some(result);
}
None => return self.finish(),
};
} else {
self.on_region = false;
let result = (self.start, self.len);
self.start += self.len;
self.len = 1;
return Some(result);
}
}
(false, true) => {
self.start += self.len;
self.len = 1;
self.on_region = true;
}
}
if self.mask == 1 {
match self.values.next() {
Some(v) => self.current_byte = v,
None => return self.finish(),
};
}
}
}
}