#[derive(Debug, Clone, PartialEq, Eq)]
enum Segment {
ZeroRun(usize),
OneRun(usize),
Literal(u64),
}
#[derive(Debug, Clone)]
pub struct CompressedMasks {
segments: Vec<Segment>,
len_words: usize,
}
impl CompressedMasks {
pub fn new() -> Self {
CompressedMasks {
segments: Vec::new(),
len_words: 0,
}
}
pub fn clear(&mut self) {
self.segments.clear();
self.len_words = 0;
}
pub fn push(&mut self, word: u64) {
use Segment::*;
self.len_words += 1;
match self.segments.last_mut() {
Some(ZeroRun(n)) if word == 0 => *n += 1,
Some(OneRun(n)) if word == !0 => *n += 1,
_ => self.segments.push(match word {
0 => ZeroRun(1),
0xffffffffffffffff => OneRun(1),
_ => Literal(word),
})
}
}
pub fn len(&self) -> usize {
self.len_words
}
pub fn count_ones(&self) -> u64 {
let mut sum: u64 = 0;
for seg in &self.segments {
match *seg {
Segment::ZeroRun(_) => {}
Segment::OneRun(count) => sum += (64 * count) as u64,
Segment::Literal(w) => sum += w.count_ones() as u64,
}
}
sum
}
pub fn get(&self, mut i: usize) -> Option<u64> {
if i >= self.len_words {
return None;
}
for seg in &self.segments {
match *seg {
Segment::ZeroRun(count) if i < count => return Some(0),
Segment::ZeroRun(count) => { i -= count; }
Segment::OneRun(count) if i < count => return Some(!0),
Segment::OneRun(count) => { i -= count; }
Segment::Literal(w) if i == 0 => return Some(w),
Segment::Literal(_) => { i -= 1; }
}
}
None
}
pub fn iter(&self) -> impl Iterator<Item = (usize, u64)> + Clone {
self.segments.iter()
.scan(0usize, |offset, seg| {
let start = *offset;
let count = match *seg {
Segment::ZeroRun(c) => c,
Segment::OneRun(c) => c,
Segment::Literal(_) => 1,
};
*offset += count;
Some((start, seg))
})
.filter(|(_, seg)| if let Segment::ZeroRun(_) = *seg {false} else {true})
.flat_map(|(i, seg)| match *seg {
Segment::ZeroRun(count) => std::iter::repeat(0).take(count),
Segment::OneRun(count) => std::iter::repeat(0xffffffffffffffff).take(count),
Segment::Literal(w) => std::iter::repeat(w).take(1),
}.enumerate().map(move |(j, m)| (i + j, m)))
}
}