From eb25648929908f3f175c663afc2a6f835f009c65 Mon Sep 17 00:00:00 2001 From: Zachary Dremann Date: Thu, 21 Mar 2024 23:34:17 -0400 Subject: [PATCH] Misc changes to match parity with bitmap/64 --- croaring/benches/benches.rs | 2 +- croaring/src/bitmap/iter.rs | 56 ++++++++++++++- croaring/src/bitmap64/iter.rs | 129 +++++++++++++++++++++++++++++----- croaring/tests/lib.rs | 2 +- 4 files changed, 168 insertions(+), 21 deletions(-) diff --git a/croaring/benches/benches.rs b/croaring/benches/benches.rs index 4f85f34..31638ce 100644 --- a/croaring/benches/benches.rs +++ b/croaring/benches/benches.rs @@ -228,7 +228,7 @@ fn random_iter(c: &mut Criterion) { // Super simple LCG iterator let mut z = 20170705; // seed std::iter::from_fn(move || { - z = (MULTIPLIER * z) % MODULUS; + z = (MULTIPLIER.wrapping_mul(z)) % MODULUS; Some(z % MAX) }) }; diff --git a/croaring/src/bitmap/iter.rs b/croaring/src/bitmap/iter.rs index b65f19e..f9007e6 100644 --- a/croaring/src/bitmap/iter.rs +++ b/croaring/src/bitmap/iter.rs @@ -10,7 +10,7 @@ use super::Bitmap; /// /// A cursor points at a single value in the bitmap, or at a "ghost" position, /// either one before the beginning of the bitmap, or one after the end of the bitmap. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct BitmapCursor<'a> { raw: ffi::roaring_uint32_iterator_t, _bitmap: PhantomData<&'a Bitmap>, @@ -403,7 +403,7 @@ impl<'a> BitmapIterator<'a> { /// # print_by_chunks(&Bitmap::of(&[1, 2, 8, 20, 1000])); /// ``` #[inline] - #[doc(alias = "roaring_read_uint32_iterator")] + #[doc(alias = "roaring_uint32_iterator_read")] pub fn next_many(&mut self, dst: &mut [u32]) -> usize { self.cursor.read_many(dst) } @@ -432,10 +432,26 @@ impl<'a> BitmapIterator<'a> { /// assert_eq!(iter.next(), None); /// ``` #[inline] - #[doc(alias = "roaring_move_uint32_iterator_equalorlarger")] + #[doc(alias = "roaring_uint32_iterator_move_equalorlarger")] pub fn reset_at_or_after(&mut self, val: u32) { self.cursor.reset_at_or_after(val); } + + /// Peek at the next value to be returned by the iterator (if any), without consuming it + /// + /// # Examples + /// + /// ``` + /// use croaring::Bitmap; + /// let mut bitmap = Bitmap::of(&[1, 2, 3]); + /// let mut iter = bitmap.iter(); + /// assert_eq!(iter.peek(), Some(1)); + /// assert_eq!(iter.next(), Some(1)); + /// ``` + #[inline] + pub fn peek(&self) -> Option { + self.cursor.current() + } } impl<'a> Iterator for BitmapIterator<'a> { @@ -499,12 +515,46 @@ impl Bitmap { } } +/// Converts this iterator into a cursor +/// +/// The cursor's current value will be the the item which would have been returned by the next call to `next()` +/// or one past the end of the bitmap if the iterator is exhausted. +/// +/// # Examples +/// +/// ``` +/// use croaring::bitmap::{Bitmap, BitmapCursor}; +/// let mut bitmap = Bitmap::of(&[1, 2, 3]); +/// let mut iter = bitmap.iter(); +/// assert_eq!(iter.peek(), Some(1)); +/// assert_eq!(iter.next(), Some(1)); +/// +/// assert_eq!(iter.peek(), Some(2)); +/// let mut cursor: BitmapCursor = iter.into(); +/// assert_eq!(cursor.current(), Some(2)); +/// ``` impl<'a> From> for BitmapCursor<'a> { fn from(iterator: BitmapIterator<'a>) -> Self { iterator.cursor } } +/// Converts this cursor into an iterator +/// +/// The next value returned by the iterator will be the current value of the cursor (if any). +/// +/// # Examples +/// +/// ``` +/// use croaring::bitmap::{Bitmap, BitmapIterator}; +/// +/// let mut bitmap = Bitmap::of(&[1, 2, 3]); +/// let mut cursor = bitmap.cursor(); +/// assert_eq!(cursor.current(), Some(1)); +/// +/// let mut iter = BitmapIterator::from(cursor); +/// assert_eq!(iter.next(), Some(1)); +/// ``` impl<'a> From> for BitmapIterator<'a> { fn from(cursor: BitmapCursor<'a>) -> Self { BitmapIterator { cursor } diff --git a/croaring/src/bitmap64/iter.rs b/croaring/src/bitmap64/iter.rs index 3f32287..5e49223 100644 --- a/croaring/src/bitmap64/iter.rs +++ b/croaring/src/bitmap64/iter.rs @@ -381,12 +381,46 @@ impl<'a> Bitmap64Cursor<'a> { } } +/// Converts this iterator into a cursor +/// +/// The cursor's current value will be the the item which would have been returned by the next call to `next()` +/// or one past the end of the bitmap if the iterator is exhausted. +/// +/// # Examples +/// +/// ``` +/// use croaring::bitmap64::{Bitmap64, Bitmap64Cursor}; +/// let mut bitmap = Bitmap64::of(&[1, 2, 3]); +/// let mut iter = bitmap.iter(); +/// assert_eq!(iter.peek(), Some(1)); +/// assert_eq!(iter.next(), Some(1)); +/// +/// assert_eq!(iter.peek(), Some(2)); +/// let mut cursor: Bitmap64Cursor = iter.into(); +/// assert_eq!(cursor.current(), Some(2)); +/// ``` impl<'a> From> for Bitmap64Cursor<'a> { fn from(iter: Bitmap64Iterator<'a>) -> Self { - iter.into_cursor() + iter.cursor } } +/// Converts this cursor into an iterator +/// +/// The next value returned by the iterator will be the current value of the cursor (if any). +/// +/// # Examples +/// +/// ``` +/// use croaring::bitmap64::{Bitmap64, Bitmap64Iterator}; +/// +/// let mut bitmap = Bitmap64::of(&[1, 2, 3]); +/// let mut cursor = bitmap.cursor(); +/// assert_eq!(cursor.current(), Some(1)); +/// +/// let mut iter = Bitmap64Iterator::from(cursor); +/// assert_eq!(iter.next(), Some(1)); +/// ``` impl<'a> From> for Bitmap64Iterator<'a> { fn from(cursor: Bitmap64Cursor<'a>) -> Self { Bitmap64Iterator { cursor } @@ -418,26 +452,92 @@ impl<'a> Bitmap64Iterator<'a> { self.cursor.move_next(); } - /// Peek at the next value to be returned by the iterator (if any), without consuming it + /// Attempt to read many values from the iterator into `dst` + /// + /// Returns the number of items read from the iterator, may be `< dst.len()` iff + /// the iterator is exhausted or `dst.len() > u64::MAX`. + /// + /// This can be much more efficient than repeated iteration. /// /// # Examples /// /// ``` /// use croaring::Bitmap64; - /// let mut bitmap = Bitmap64::of(&[1, 2, 3]); + /// + /// let mut bitmap: Bitmap64 = Bitmap64::new(); + /// bitmap.add_range(0..100); + /// bitmap.add(222); + /// bitmap.add(555); + /// + /// let mut buf = [0; 100]; /// let mut iter = bitmap.iter(); - /// assert_eq!(iter.peek(), Some(1)); - /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next_many(&mut buf), 100); + /// // Get the first 100 items, from the original range added + /// for (i, item) in buf.iter().enumerate() { + /// assert_eq!(*item, i as u64); + /// } + /// // Calls to next_many() can be interleaved with calls to next() + /// assert_eq!(iter.next(), Some(222)); + /// assert_eq!(iter.next_many(&mut buf), 1); + /// assert_eq!(buf[0], 555); + /// + /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.next_many(&mut buf), 0); + /// ``` + /// + /// ``` + /// use croaring::Bitmap64; + /// + /// fn print_by_chunks(bitmap: &Bitmap64) { + /// let mut buf = [0; 1024]; + /// let mut iter = bitmap.iter(); + /// loop { + /// let n = iter.next_many(&mut buf); + /// if n == 0 { + /// break; + /// } + /// println!("{:?}", &buf[..n]); + /// } + /// } + /// + /// # print_by_chunks(&Bitmap64::of(&[1, 2, 8, 20, 1000])); /// ``` #[inline] - pub fn peek(&self) -> Option { - self.cursor.current() + #[doc(alias = "roaring64_iterator_read")] + pub fn next_many(&mut self, dst: &mut [u64]) -> usize { + self.cursor.read_many(dst) } - /// Converts this iterator into a cursor + /// Reset the iterator to the first value `>= val` /// - /// The cursor's current value will be the the item which would have been returned by the next call to `next()` - /// or one past the end of the bitmap if the iterator is exhausted. + /// This can move the iterator forwards or backwards. + /// + /// # Examples + /// ``` + /// use croaring::Bitmap64; + /// + /// let mut bitmap = Bitmap64::of(&[0, 1, 100, 1000, u64::MAX]); + /// let mut iter = bitmap.iter(); + /// iter.reset_at_or_after(0); + /// assert_eq!(iter.next(), Some(0)); + /// iter.reset_at_or_after(0); + /// assert_eq!(iter.next(), Some(0)); + /// + /// iter.reset_at_or_after(101); + /// assert_eq!(iter.next(), Some(1000)); + /// assert_eq!(iter.next(), Some(u64::MAX)); + /// assert_eq!(iter.next(), None); + /// iter.reset_at_or_after(u64::MAX); + /// assert_eq!(iter.next(), Some(u64::MAX)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[doc(alias = "roaring64_iterator_move_equalorlarger")] + pub fn reset_at_or_after(&mut self, val: u64) { + self.cursor.reset_at_or_after(val); + } + + /// Peek at the next value to be returned by the iterator (if any), without consuming it /// /// # Examples /// @@ -447,13 +547,10 @@ impl<'a> Bitmap64Iterator<'a> { /// let mut iter = bitmap.iter(); /// assert_eq!(iter.peek(), Some(1)); /// assert_eq!(iter.next(), Some(1)); - /// - /// assert_eq!(iter.peek(), Some(2)); - /// let mut cursor = iter.into_cursor(); - /// assert_eq!(cursor.current(), Some(2)); /// ``` - pub fn into_cursor(self) -> Bitmap64Cursor<'a> { - self.cursor + #[inline] + pub fn peek(&self) -> Option { + self.cursor.current() } } diff --git a/croaring/tests/lib.rs b/croaring/tests/lib.rs index da8388f..f0b8fe9 100644 --- a/croaring/tests/lib.rs +++ b/croaring/tests/lib.rs @@ -116,7 +116,7 @@ fn empty_cursor() { #[test] fn cursor_return_from_the_edge() { - let mut bitmap = Bitmap::from([1, 2, u32::MAX]); + let bitmap = Bitmap::from([1, 2, u32::MAX]); let mut cursor = bitmap.cursor_to_last(); assert_eq!(cursor.current(), Some(u32::MAX)); assert_eq!(cursor.next(), None);