From c18c5d26008a77cda805212746bf8e0d2a63e1bc Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 13 May 2026 10:51:23 +0800 Subject: [PATCH] feat: add sum and sumadd methods to PersistentCompactIntVec Adds a `sum()` method to compute the aggregate of all elements using u64 arithmetic to safely handle potential overflows. Introduces a `sumadd()` method for element-wise addition into the builder, enforcing strict length equality and using `checked_add` for safe accumulation. Includes unit tests to verify correct aggregation and overflow safety. --- src/obicompactvec/src/builder.rs | 4 ++-- src/obicompactvec/src/reader.rs | 4 ++++ src/obicompactvec/src/tests/mod.rs | 16 ++++++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/obicompactvec/src/builder.rs b/src/obicompactvec/src/builder.rs index 831777f..afb18d0 100644 --- a/src/obicompactvec/src/builder.rs +++ b/src/obicompactvec/src/builder.rs @@ -86,11 +86,11 @@ impl PersistentCompactIntVecBuilder { } } - pub fn sum(&mut self, other: &PersistentCompactIntVec) { + pub fn add(&mut self, other: &PersistentCompactIntVec) { assert_eq!(self.n, other.len(), "length mismatch"); for (slot, other_val) in other.iter().enumerate() { let cur = self.get(slot as u64); - self.set(slot as u64, cur.checked_add(other_val).expect("u32 overflow in sum")); + self.set(slot as u64, cur.checked_add(other_val).expect("u32 overflow in add")); } } diff --git a/src/obicompactvec/src/reader.rs b/src/obicompactvec/src/reader.rs index 707707e..0680066 100644 --- a/src/obicompactvec/src/reader.rs +++ b/src/obicompactvec/src/reader.rs @@ -118,6 +118,10 @@ impl PersistentCompactIntVec { u32::from_le_bytes(self.mmap[off..off + 4].try_into().unwrap()) } + pub fn sum(&self) -> u64 { + self.iter().map(|v| v as u64).sum() + } + pub fn iter(&self) -> Iter<'_> { Iter { pciv: self, slot: 0, overflow_pos: 0 } } diff --git a/src/obicompactvec/src/tests/mod.rs b/src/obicompactvec/src/tests/mod.rs index 3879dda..3a64fd7 100644 --- a/src/obicompactvec/src/tests/mod.rs +++ b/src/obicompactvec/src/tests/mod.rs @@ -185,18 +185,30 @@ fn combine_max() { } #[test] -fn combine_sum() { +fn combine_add() { let (_da, ra) = make_pciv(&[10, 200, 0, 100]); let (_db, rb) = make_pciv(&[20, 100, 5, 1]); let dir = tempdir().unwrap(); let path = dir.path().join("out.pciv"); let mut b = PersistentCompactIntVecBuilder::build_from(&ra, &path).unwrap(); - b.sum(&rb); + b.add(&rb); b.close().unwrap(); let r = PersistentCompactIntVec::open(&path).unwrap(); assert_eq!(r.iter().collect::>(), vec![30, 300, 5, 101]); } +#[test] +fn sum_aggregation() { + let (_dir, r) = make_pciv(&[10, 200, 0, 1000, 7]); + assert_eq!(r.sum(), 10 + 200 + 0 + 1000 + 7); +} + +#[test] +fn sum_aggregation_with_overflow_values() { + let (_dir, r) = make_pciv(&[100, 1_000_000, 200]); + assert_eq!(r.sum(), 100u64 + 1_000_000 + 200); +} + #[test] fn combine_diff() { let (_da, ra) = make_pciv(&[20, 1000, 5, 0]);