feat(obicompactvec): implement Iterator for PersistentCompactIntVec
Add an `Iter` struct that implements `Iterator` and `ExactSizeIterator` to enable idiomatic traversal of `&PersistentCompactIntVec`. The iterator maintains `slot` and `overflow_pos` state to correctly yield `u32` values from both primary and overflow memory regions. Includes three unit tests validating iteration correctness against direct indexing, accurate `len()` tracking, and proper reference-based iteration.
This commit is contained in:
@@ -104,4 +104,49 @@ impl PersistentCompactIntVec {
|
||||
let off = self.data_offset + i * 8 + 4;
|
||||
u32::from_le_bytes(self.mmap[off..off + 4].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
Iter { pciv: self, slot: 0, overflow_pos: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a PersistentCompactIntVec {
|
||||
type Item = u32;
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
fn into_iter(self) -> Iter<'a> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a> {
|
||||
pciv: &'a PersistentCompactIntVec,
|
||||
slot: usize,
|
||||
overflow_pos: usize,
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Iter<'_> {}
|
||||
|
||||
impl Iterator for Iter<'_> {
|
||||
type Item = u32;
|
||||
|
||||
fn next(&mut self) -> Option<u32> {
|
||||
if self.slot >= self.pciv.n {
|
||||
return None;
|
||||
}
|
||||
let v = self.pciv.mmap[self.pciv.primary_offset + self.slot];
|
||||
self.slot += 1;
|
||||
if v < 255 {
|
||||
Some(v as u32)
|
||||
} else {
|
||||
let val = self.pciv.data_value(self.overflow_pos);
|
||||
self.overflow_pos += 1;
|
||||
Some(val)
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let remaining = self.pciv.n - self.slot;
|
||||
(remaining, Some(remaining))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,52 @@ fn sparse_index_built_for_many_overflows() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_matches_get() {
|
||||
let values = [(0u64, 255u32), (1, 1000), (2, 50), (3, 1_313_691), (4, 7), (5, 42)];
|
||||
let n = 6;
|
||||
let dir = tempdir().unwrap();
|
||||
let path = dir.path().join("test.pciv");
|
||||
let mut b = PersistentCompactIntVecBuilder::new(n);
|
||||
for &(slot, v) in &values {
|
||||
b.set(slot, v);
|
||||
}
|
||||
b.close(&path).unwrap();
|
||||
let r = PersistentCompactIntVec::open(&path).unwrap();
|
||||
|
||||
let via_iter: Vec<u32> = r.iter().collect();
|
||||
let via_get: Vec<u32> = (0..n as u64).map(|s| r.get(s)).collect();
|
||||
assert_eq!(via_iter, via_get);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_size_hint_exact() {
|
||||
let dir = tempdir().unwrap();
|
||||
let path = dir.path().join("test.pciv");
|
||||
let mut b = PersistentCompactIntVecBuilder::new(5);
|
||||
b.set(2, 1000);
|
||||
b.close(&path).unwrap();
|
||||
let r = PersistentCompactIntVec::open(&path).unwrap();
|
||||
let mut it = r.iter();
|
||||
assert_eq!(it.len(), 5);
|
||||
it.next();
|
||||
assert_eq!(it.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_iter_for_ref() {
|
||||
let dir = tempdir().unwrap();
|
||||
let path = dir.path().join("test.pciv");
|
||||
let mut b = PersistentCompactIntVecBuilder::new(3);
|
||||
b.set(0, 10);
|
||||
b.set(1, 500);
|
||||
b.set(2, 30);
|
||||
b.close(&path).unwrap();
|
||||
let r = PersistentCompactIntVec::open(&path).unwrap();
|
||||
let collected: Vec<u32> = (&r).into_iter().collect();
|
||||
assert_eq!(collected, vec![10, 500, 30]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_large_dataset() {
|
||||
let n = 1000usize;
|
||||
|
||||
Reference in New Issue
Block a user