From 24a4bdac562a2df67bdde8e9dc9f18bf86a023b5 Mon Sep 17 00:00:00 2001 From: Jan-Paul Bultmann <74891396+somethingelseentirely@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:14:01 +0200 Subject: [PATCH] Split vector inspection tests --- CHANGELOG.md | 2 ++ INVENTORY.md | 1 - src/bit_vector/bit_vector.rs | 56 +++++++++++++++++++++++++++++++ src/int_vectors/compact_vector.rs | 18 ++++++++++ src/int_vectors/dacs_byte.rs | 30 ++++++++++++++++- 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6511301..89e3993 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,3 +43,5 @@ - Fixed a stale doc link referencing the old `bit_vectors` module. - Removed completed documentation cleanup tasks from `INVENTORY.md`. - Fixed a typo in `bench/README.md`. +- Added iterators and `to_vec` helpers for inspecting built vectors. +- Split inspection tests so each assertion stands alone. diff --git a/INVENTORY.md b/INVENTORY.md index a32cefa..854c345 100644 --- a/INVENTORY.md +++ b/INVENTORY.md @@ -4,7 +4,6 @@ - None at the moment. ## Desired Functionality -- Expose utilities for inspecting and debugging built vectors. - Provide more usage examples and documentation. - Evaluate additional succinct data structures to include. - Investigate alternative dense-select index strategies to replace removed `DArrayIndex`. diff --git a/src/bit_vector/bit_vector.rs b/src/bit_vector/bit_vector.rs index 64e7e4b..f9f98ca 100644 --- a/src/bit_vector/bit_vector.rs +++ b/src/bit_vector/bit_vector.rs @@ -322,6 +322,37 @@ pub struct BitVector { pub index: I, } +/// Iterator over bits in a [`BitVector`]. +pub struct Iter<'a, I> { + bv: &'a BitVector, + pos: usize, +} + +impl<'a, I> Iter<'a, I> { + /// Creates a new iterator. + pub const fn new(bv: &'a BitVector) -> Self { + Self { bv, pos: 0 } + } +} + +impl Iterator for Iter<'_, I> { + type Item = bool; + + fn next(&mut self) -> Option { + if self.pos < self.bv.len() { + let bit = self.bv.access(self.pos).unwrap(); + self.pos += 1; + Some(bit) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.bv.len(), Some(self.bv.len())) + } +} + impl BitVector { /// Creates a new wrapper from data and index. pub const fn new(data: BitVectorData, index: I) -> Self { @@ -337,6 +368,16 @@ impl BitVector { pub fn get_bits(&self, pos: usize, len: usize) -> Option { self.data.get_bits(pos, len) } + + /// Creates an iterator over all bits. + pub const fn iter(&self) -> Iter { + Iter { bv: self, pos: 0 } + } + + /// Collects all bits into a `Vec` for inspection. + pub fn to_vec(&self) -> Vec { + self.iter().collect() + } } impl NumBits for BitVector { @@ -433,4 +474,19 @@ mod tests { let bv: BitVector = builder.freeze::(); assert_eq!(bv.data.get_bits(61, 7).unwrap(), 0b0111110); } + + #[test] + fn iter_collects() { + let data = BitVectorData::from_bits([true, false, true]); + let bv = BitVector::new(data, NoIndex); + let collected: Vec = bv.iter().collect(); + assert_eq!(collected, vec![true, false, true]); + } + + #[test] + fn to_vec_collects() { + let data = BitVectorData::from_bits([true, false, true]); + let bv = BitVector::new(data, NoIndex); + assert_eq!(bv.to_vec(), vec![true, false, true]); + } } diff --git a/src/int_vectors/compact_vector.rs b/src/int_vectors/compact_vector.rs index b700e61..0ff5965 100644 --- a/src/int_vectors/compact_vector.rs +++ b/src/int_vectors/compact_vector.rs @@ -384,6 +384,11 @@ impl CompactVector { Iter::new(self) } + /// Collects all integers into a `Vec` for inspection. + pub fn to_vec(&self) -> Vec { + self.iter().collect() + } + /// Gets the number of integers. #[inline(always)] pub const fn len(&self) -> usize { @@ -645,4 +650,17 @@ mod tests { let cv = CompactVector::from_int(42, 1, 64).unwrap(); assert_eq!(cv.get_int(0), Some(42)); } + + #[test] + fn iter_collects() { + let cv = CompactVector::from_slice(&[1, 2, 3]).unwrap(); + let collected: Vec = cv.iter().collect(); + assert_eq!(collected, vec![1, 2, 3]); + } + + #[test] + fn to_vec_collects() { + let cv = CompactVector::from_slice(&[1, 2, 3]).unwrap(); + assert_eq!(cv.to_vec(), vec![1, 2, 3]); + } } diff --git a/src/int_vectors/dacs_byte.rs b/src/int_vectors/dacs_byte.rs index 388b6c1..a3ba30f 100644 --- a/src/int_vectors/dacs_byte.rs +++ b/src/int_vectors/dacs_byte.rs @@ -52,7 +52,7 @@ const LEVEL_MASK: usize = (1 << LEVEL_WIDTH) - 1; /// /// - N. R. Brisaboa, S. Ladra, and G. Navarro, "DACs: Bringing direct access to variable-length /// codes." Information Processing & Management, 49(1), 392-404, 2013. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct DacsByte { data: Vec>, flags: Vec>, @@ -151,6 +151,11 @@ impl DacsByte { Iter::new(self) } + /// Collects all integers into a `Vec` for inspection. + pub fn to_vec(&self) -> Vec { + self.iter().collect() + } + /// Gets the number of integers. #[inline(always)] pub fn len(&self) -> usize { @@ -260,6 +265,16 @@ impl<'a> Iter<'a> { } } +impl std::fmt::Debug for DacsByte { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DacsByte") + .field("ints", &self.to_vec()) + .field("len", &self.len()) + .field("num_levels", &self.num_levels()) + .finish() + } +} + impl Iterator for Iter<'_> { type Item = usize; @@ -360,6 +375,19 @@ mod tests { assert_eq!(seq.access(3), Some(0)); } + #[test] + fn iter_collects() { + let seq = DacsByte::from_slice(&[5, 7]).unwrap(); + let collected: Vec = seq.iter().collect(); + assert_eq!(collected, vec![5, 7]); + } + + #[test] + fn to_vec_collects() { + let seq = DacsByte::from_slice(&[5, 7]).unwrap(); + assert_eq!(seq.to_vec(), vec![5, 7]); + } + #[test] fn test_from_slice_uncastable() { let e = DacsByte::from_slice(&[u128::MAX]);