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;
|
let off = self.data_offset + i * 8 + 4;
|
||||||
u32::from_le_bytes(self.mmap[off..off + 4].try_into().unwrap())
|
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]
|
#[test]
|
||||||
fn mixed_large_dataset() {
|
fn mixed_large_dataset() {
|
||||||
let n = 1000usize;
|
let n = 1000usize;
|
||||||
|
|||||||
Reference in New Issue
Block a user