From 73714f845bb7fe3243a7cc804a899ffdf5855d37 Mon Sep 17 00:00:00 2001 From: Oskar Goldhahn Date: Wed, 29 May 2024 20:51:47 +0200 Subject: [PATCH] add dedicated fold and rfold impls add test for `fold` also add test for treemap use closures directly --- src/bitmap/iter.rs | 34 +++++++++++++++++++++ src/treemap/iter.rs | 70 +++++++++++++++++++++++++++++++++++++++++++ tests/iter.rs | 14 +++++++++ tests/treemap_iter.rs | 14 +++++++++ 4 files changed, 132 insertions(+) diff --git a/src/bitmap/iter.rs b/src/bitmap/iter.rs index ac85fa33..60e1cb50 100644 --- a/src/bitmap/iter.rs +++ b/src/bitmap/iter.rs @@ -46,6 +46,15 @@ impl Iterator for Iter<'_> { (usize::MAX, None) } } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } impl DoubleEndedIterator for Iter<'_> { @@ -53,6 +62,14 @@ impl DoubleEndedIterator for Iter<'_> { self.size_hint = self.size_hint.saturating_sub(1); self.inner.next_back() } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } } #[cfg(target_pointer_width = "64")] @@ -77,6 +94,15 @@ impl Iterator for IntoIter { (usize::MAX, None) } } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } impl DoubleEndedIterator for IntoIter { @@ -84,6 +110,14 @@ impl DoubleEndedIterator for IntoIter { self.size_hint = self.size_hint.saturating_sub(1); self.inner.next_back() } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } } #[cfg(target_pointer_width = "64")] diff --git a/src/treemap/iter.rs b/src/treemap/iter.rs index afe1fb42..96ccb00d 100644 --- a/src/treemap/iter.rs +++ b/src/treemap/iter.rs @@ -16,12 +16,30 @@ impl<'a> Iterator for To64Iter<'a> { fn next(&mut self) -> Option { self.inner.next().map(|n| util::join(self.hi, n)) } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, move |b, lo| f(b, ((self.hi as u64) << 32) + (lo as u64))) + } } impl DoubleEndedIterator for To64Iter<'_> { fn next_back(&mut self) -> Option { self.inner.next_back().map(|n| util::join(self.hi, n)) } + + #[inline] + fn rfold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.rfold(init, move |b, lo| f(b, ((self.hi as u64) << 32) + (lo as u64))) + } } fn to64iter<'a>(t: (&'a u32, &'a RoaringBitmap)) -> To64Iter<'a> { @@ -38,12 +56,30 @@ impl Iterator for To64IntoIter { fn next(&mut self) -> Option { self.inner.next().map(|n| util::join(self.hi, n)) } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, move |b, lo| f(b, ((self.hi as u64) << 32) + (lo as u64))) + } } impl DoubleEndedIterator for To64IntoIter { fn next_back(&mut self) -> Option { self.inner.next_back().map(|n| util::join(self.hi, n)) } + + #[inline] + fn rfold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.rfold(init, move |b, lo| f(b, ((self.hi as u64) << 32) + (lo as u64))) + } } fn to64intoiter(t: (u32, RoaringBitmap)) -> To64IntoIter { @@ -104,6 +140,15 @@ impl<'a> Iterator for Iter<'a> { (usize::MAX, None) } } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } impl DoubleEndedIterator for Iter<'_> { @@ -111,6 +156,14 @@ impl DoubleEndedIterator for Iter<'_> { self.size_hint = self.size_hint.saturating_sub(1); self.inner.next_back() } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } } #[cfg(target_pointer_width = "64")] @@ -135,6 +188,15 @@ impl Iterator for IntoIter { (usize::MAX, None) } } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } impl DoubleEndedIterator for IntoIter { @@ -142,6 +204,14 @@ impl DoubleEndedIterator for IntoIter { self.size_hint = self.size_hint.saturating_sub(1); self.inner.next_back() } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } } #[cfg(target_pointer_width = "64")] diff --git a/tests/iter.rs b/tests/iter.rs index 7d4e5809..86a83245 100644 --- a/tests/iter.rs +++ b/tests/iter.rs @@ -67,6 +67,20 @@ proptest! { } } +proptest! { + #[test] + fn fold(values in btree_set(any::(), ..=10_000)) { + let bitmap = RoaringBitmap::from_sorted_iter(values.iter().cloned()).unwrap(); + let mut val_iter = values.into_iter(); + // `Iterator::all` uses currently unimplementable `try_fold`, we test `fold` + #[allow(clippy::unnecessary_fold)] + let r = bitmap.into_iter().fold(true, |b, i| { + b && i == val_iter.next().unwrap() + }); + assert!(r) + } +} + #[test] fn rev_array() { let values = 0..100; diff --git a/tests/treemap_iter.rs b/tests/treemap_iter.rs index ef328a58..be5b9a6e 100644 --- a/tests/treemap_iter.rs +++ b/tests/treemap_iter.rs @@ -77,6 +77,20 @@ proptest! { } } +proptest! { + #[test] + fn fold(values in btree_set(any::(), ..=10_000)) { + let bitmap = RoaringTreemap::from_sorted_iter(values.iter().cloned()).unwrap(); + let mut val_iter = values.into_iter(); + // `Iterator::all` uses currently unimplementable `try_fold`, we test `fold` + #[allow(clippy::unnecessary_fold)] + let r = bitmap.into_iter().fold(true, |b, i| { + b && i == val_iter.next().unwrap() + }); + assert!(r) + } +} + #[test] fn rev() { let values = (1..3)