use crate::{Chunk, SparseMap, BITS_PER_WORD, CHUNK_BITS, WORDS_PER_CHUNK};
use alloc::collections::btree_map;
enum Cursor<'a> {
Run { next: u64, last: u64, done: bool },
Dense {
base: u64,
word: usize,
bits: u64,
words: &'a [u64; WORDS_PER_CHUNK],
},
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a> {
chunks: btree_map::Iter<'a, u64, Chunk>,
cur: Option<Cursor<'a>>,
}
impl<'a> Iter<'a> {
pub(crate) fn new(map: &'a SparseMap) -> Self {
Iter {
chunks: map.chunks.iter(),
cur: None,
}
}
fn load_next_chunk(&mut self) -> bool {
match self.chunks.next() {
Some((&base, Chunk::Run(n))) => {
self.cur = Some(Cursor::Run {
next: base,
last: base + (u64::from(*n) * CHUNK_BITS - 1),
done: false,
});
true
}
Some((&base, Chunk::Dense(w))) => {
self.cur = Some(Cursor::Dense {
base,
word: 0,
bits: w[0],
words: w,
});
true
}
None => false,
}
}
}
impl Iterator for Iter<'_> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
loop {
match &mut self.cur {
Some(Cursor::Run { next, last, done }) => {
if !*done {
let v = *next;
if *next == *last {
*done = true;
} else {
*next += 1;
}
return Some(v);
}
self.cur = None;
}
Some(Cursor::Dense {
base,
word,
bits,
words,
}) => {
while *bits == 0 {
*word += 1;
if *word >= WORDS_PER_CHUNK {
break;
}
*bits = words[*word];
}
if *word < WORDS_PER_CHUNK {
let tz = bits.trailing_zeros();
*bits &= *bits - 1; return Some(*base + *word as u64 * BITS_PER_WORD + u64::from(tz));
}
self.cur = None;
}
None => {
if !self.load_next_chunk() {
return None;
}
}
}
}
}
}
impl<'a> IntoIterator for &'a SparseMap {
type Item = u64;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
impl SparseMap {
pub fn iter(&self) -> Iter<'_> {
Iter::new(self)
}
#[must_use]
pub fn to_vec(&self) -> alloc::vec::Vec<u64> {
self.iter().collect()
}
#[cfg(feature = "bitvec")]
#[must_use]
pub fn to_bitvec(&self, lo: u64, hi: u64) -> bitvec::vec::BitVec {
use bitvec::vec::BitVec;
if lo >= hi {
return BitVec::new();
}
let len = (hi - lo) as usize;
let mut bv = BitVec::repeat(false, len);
for b in self.iter() {
if b < lo {
continue;
}
if b >= hi {
break;
}
bv.set((b - lo) as usize, true);
}
bv
}
}