From eb26e0dc3cb387f56e0d4fb1dfe72da58e957a1e 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 --- src/bitmap/iter.rs | 34 ++++++++++++++++ src/treemap/iter.rs | 90 +++++++++++++++++++++++++++++++++++++++++++ tests/iter.rs | 14 +++++++ tests/treemap_iter.rs | 14 +++++++ 4 files changed, 152 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..d834a9b4 100644 --- a/src/treemap/iter.rs +++ b/src/treemap/iter.rs @@ -16,12 +16,40 @@ 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, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + #[inline] + fn f_with_hi(mut f: impl FnMut(B, u64) -> B, hi: u32) -> impl FnMut(B, u32) -> B { + move |b, lo| f(b, ((hi as u64) << 32) + (lo as u64)) + } + + self.inner.fold(init, f_with_hi(f, self.hi)) + } } 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, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + #[inline] + fn f_with_hi(mut f: impl FnMut(B, u64) -> B, hi: u32) -> impl FnMut(B, u32) -> B { + move |b, lo| f(b, ((hi as u64) << 32) + (lo as u64)) + } + + self.inner.rfold(init, f_with_hi(f, self.hi)) + } } fn to64iter<'a>(t: (&'a u32, &'a RoaringBitmap)) -> To64Iter<'a> { @@ -38,12 +66,40 @@ 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, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + #[inline] + fn f_with_hi(mut f: impl FnMut(B, u64) -> B, hi: u32) -> impl FnMut(B, u32) -> B { + move |b, lo| f(b, ((hi as u64) << 32) + (lo as u64)) + } + + self.inner.fold(init, f_with_hi(f, self.hi)) + } } 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, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + #[inline] + fn f_with_hi(mut f: impl FnMut(B, u64) -> B, hi: u32) -> impl FnMut(B, u32) -> B { + move |b, lo| f(b, ((hi as u64) << 32) + (lo as u64)) + } + + self.inner.rfold(init, f_with_hi(f, self.hi)) + } } fn to64intoiter(t: (u32, RoaringBitmap)) -> To64IntoIter { @@ -104,6 +160,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 +176,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 +208,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 +224,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)