diff --git a/roaring/src/bitmap/container.rs b/roaring/src/bitmap/container.rs index 3ab1e5ad..9b11cd57 100644 --- a/roaring/src/bitmap/container.rs +++ b/roaring/src/bitmap/container.rs @@ -295,11 +295,15 @@ impl IntoIterator for Container { } } -impl<'a> Iterator for Iter<'a> { +impl Iterator for Iter<'_> { type Item = u32; fn next(&mut self) -> Option { self.inner.next().map(|i| util::join(self.key, i)) } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } impl DoubleEndedIterator for Iter<'_> { @@ -313,3 +317,20 @@ impl fmt::Debug for Container { format!("Container<{:?} @ {:?}>", self.len(), self.key).fmt(formatter) } } + +impl Iter<'_> { + pub fn empty() -> Self { + Self { key: 0, inner: store::Iter::empty() } + } + + #[inline] + pub fn peek(&mut self) -> Option { + self.inner.peek().map(|i| util::join(self.key, i)) + } +} + +impl AsRef for Container { + fn as_ref(&self) -> &Container { + self + } +} diff --git a/roaring/src/bitmap/iter.rs b/roaring/src/bitmap/iter.rs index 59463a21..678e3a06 100644 --- a/roaring/src/bitmap/iter.rs +++ b/roaring/src/bitmap/iter.rs @@ -1,47 +1,59 @@ -use alloc::vec; -use core::iter; -use core::slice; - use super::container::Container; use crate::{NonSortedIntegers, RoaringBitmap}; +use crate::bitmap::container; #[cfg(not(feature = "std"))] use alloc::vec::Vec; -/// An iterator for `RoaringBitmap`. -pub struct Iter<'a> { - inner: iter::Flatten>, - size_hint: u64, -} +use alloc::collections::vec_deque::VecDeque; +use iter_inner::IterInternal; /// An iterator for `RoaringBitmap`. -pub struct IntoIter { - inner: iter::Flatten>, +pub struct Iter<'a> { + containers: &'a [Container], + iter_front: container::Iter<'a>, + iter_back: Option>, size_hint: u64, } - -impl Iter<'_> { - fn new(containers: &[Container]) -> Iter { +impl<'a> Iter<'a> { + fn new(containers: &'a [Container]) -> Self { let size_hint = containers.iter().map(|c| c.len()).sum(); - Iter { inner: containers.iter().flatten(), size_hint } + if let Some((first, rest)) = containers.split_first() { + Self { containers: rest, iter_front: first.into_iter(), iter_back: None, size_hint } + } else { + Self { + containers: &[], + iter_front: container::Iter::empty(), + iter_back: None, + size_hint, + } + } } -} -impl IntoIter { - fn new(containers: Vec) -> IntoIter { - let size_hint = containers.iter().map(|c| c.len()).sum(); - IntoIter { inner: containers.into_iter().flatten(), size_hint } + /// Advance the iterator to the first position where the item has a value >= `n` + /// + /// # Examples + /// + /// ```rust + /// use roaring::RoaringBitmap; + /// use core::iter::FromIterator; + /// + /// let bitmap = (1..3).collect::(); + /// let mut iter = bitmap.iter(); + /// iter.advance_to(2); + /// + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), None); + /// ``` + pub fn advance_to(&mut self, n: u32) { + self.advance_to_inner(n); } } - impl Iterator for Iter<'_> { type Item = u32; - fn next(&mut self) -> Option { - self.size_hint = self.size_hint.saturating_sub(1); - self.inner.next() + self.next_inner() } - fn size_hint(&self) -> (usize, Option) { if self.size_hint < usize::MAX as u64 { (self.size_hint as usize, Some(self.size_hint as usize)) @@ -49,47 +61,81 @@ 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) + self.fold_inner(init, f) } } - impl DoubleEndedIterator for Iter<'_> { fn next_back(&mut self) -> Option { - self.size_hint = self.size_hint.saturating_sub(1); - self.inner.next_back() + self.next_back_inner() } #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc + fn rfold(self, init: Acc, f: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - self.inner.rfold(init, fold) + self.rfold_inner(init, f) } } - #[cfg(target_pointer_width = "64")] impl ExactSizeIterator for Iter<'_> { fn len(&self) -> usize { self.size_hint as usize } } +/// An iterator for `RoaringBitmap`. +pub struct IntoIter { + containers: VecDeque, + iter_front: container::Iter<'static>, + iter_back: Option>, + size_hint: u64, +} +impl IntoIter { + fn new(containers: Vec) -> Self { + let size_hint = containers.iter().map(|c| c.len()).sum(); + let mut containers = VecDeque::from(containers); + if let Some(first) = containers.pop_front() { + Self { containers, iter_front: first.into_iter(), iter_back: None, size_hint } + } else { + Self { + containers: Default::default(), + iter_front: container::Iter::empty(), + iter_back: None, + size_hint, + } + } + } + /// Advance the iterator to the first position where the item has a value >= `n` + /// + /// # Examples + /// + /// ```rust + /// use roaring::RoaringBitmap; + /// use core::iter::FromIterator; + /// + /// let bitmap = (1..3).collect::(); + /// let mut iter = bitmap.into_iter(); + /// iter.advance_to(2); + /// + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), None); + /// ``` + pub fn advance_to(&mut self, n: u32) { + self.advance_to_inner(n) + } +} impl Iterator for IntoIter { type Item = u32; - fn next(&mut self) -> Option { - self.size_hint = self.size_hint.saturating_sub(1); - self.inner.next() + self.next_inner() } - fn size_hint(&self) -> (usize, Option) { if self.size_hint < usize::MAX as u64 { (self.size_hint as usize, Some(self.size_hint as usize)) @@ -97,32 +143,27 @@ 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) + self.fold_inner(init, f) } } - impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { - self.size_hint = self.size_hint.saturating_sub(1); - self.inner.next_back() + self.next_back_inner() } - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc + fn rfold(self, init: Acc, f: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - self.inner.rfold(init, fold) + self.rfold_inner(init, f) } } - #[cfg(target_pointer_width = "64")] impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { @@ -150,31 +191,25 @@ impl RoaringBitmap { Iter::new(&self.containers) } } - impl<'a> IntoIterator for &'a RoaringBitmap { type Item = u32; type IntoIter = Iter<'a>; - fn into_iter(self) -> Iter<'a> { self.iter() } } - impl IntoIterator for RoaringBitmap { type Item = u32; type IntoIter = IntoIter; - fn into_iter(self) -> IntoIter { IntoIter::new(self.containers) } } - impl From<[u32; N]> for RoaringBitmap { fn from(arr: [u32; N]) -> Self { RoaringBitmap::from_iter(arr) } } - impl FromIterator for RoaringBitmap { fn from_iter>(iterator: I) -> RoaringBitmap { let mut rb = RoaringBitmap::new(); @@ -182,7 +217,6 @@ impl FromIterator for RoaringBitmap { rb } } - impl<'a> FromIterator<&'a u32> for RoaringBitmap { fn from_iter>(iterator: I) -> RoaringBitmap { let mut rb = RoaringBitmap::new(); @@ -190,7 +224,6 @@ impl<'a> FromIterator<&'a u32> for RoaringBitmap { rb } } - impl Extend for RoaringBitmap { fn extend>(&mut self, iterator: I) { for value in iterator { @@ -198,7 +231,6 @@ impl Extend for RoaringBitmap { } } } - impl<'a> Extend<&'a u32> for RoaringBitmap { fn extend>(&mut self, iterator: I) { for value in iterator { @@ -206,7 +238,6 @@ impl<'a> Extend<&'a u32> for RoaringBitmap { } } } - impl RoaringBitmap { /// Create the set from a sorted iterator. Values must be sorted and deduplicated. /// @@ -243,7 +274,6 @@ impl RoaringBitmap { let mut rb = RoaringBitmap::new(); rb.append(iterator).map(|_| rb) } - /// Extend the set with a sorted iterator. /// /// The values of the iterator must be ordered and strictly greater than the greatest value @@ -267,24 +297,16 @@ impl RoaringBitmap { &mut self, iterator: I, ) -> Result { - // Name shadowed to prevent accidentally referencing the param let mut iterator = iterator.into_iter(); - let mut prev = match (iterator.next(), self.max()) { (None, _) => return Ok(0), (Some(first), Some(max)) if first <= max => { - return Err(NonSortedIntegers { valid_until: 0 }) + return Err(NonSortedIntegers { valid_until: 0 }); } (Some(first), _) => first, }; - - // It is now guaranteed that so long as the values of the iterator are - // monotonically increasing they must also be the greatest in the set. - self.push_unchecked(prev); - let mut count = 1; - for value in iterator { if value <= prev { return Err(NonSortedIntegers { valid_until: count }); @@ -294,7 +316,337 @@ impl RoaringBitmap { count += 1; } } - Ok(count) } } + +mod iter_inner { + use crate::bitmap::container::Container; + use crate::bitmap::{container, util, IntoIter, Iter}; + use core::slice; + + pub(super) trait IterInternal<'a> { + type Container: IntoIterator, Item = u32> + AsRef; + + type ContainerIterator: Iterator + DoubleEndedIterator; + type IntoContainerIterator: IntoIterator; + + fn pop_container_front(&mut self) -> Option; + fn pop_container_back(&mut self) -> Option; + + fn drain_containers_until(&mut self, index: usize); + + fn clear_containers(&mut self); + + fn find_container(&self, key: u16) -> Option; + + fn iter_front_mut(&mut self) -> &mut container::Iter<'a>; + fn iter_back_mut(&mut self) -> &mut Option>; + + fn dec_size_hint(&mut self, n: u64); + fn set_size_hint(&mut self, n: u64); + + fn empty_inner_iter() -> container::Iter<'static>; + + fn decompose( + self, + ) -> (container::Iter<'a>, Option>, Self::IntoContainerIterator); + + #[inline] + fn next_inner(&mut self) -> Option { + self.dec_size_hint(1); + loop { + if let item @ Some(_) = self.iter_front_mut().next() { + return item; + } + if self.advance_container().is_some() { + continue; + } else { + return None; + } + } + } + + #[inline] + fn next_back_inner(&mut self) -> Option { + self.dec_size_hint(1); + loop { + if let Some(iter) = self.iter_back_mut() { + if let item @ Some(_) = iter.next_back() { + return item; + } + } + if self.advance_container_back().is_some() { + continue; + } else { + return None; + } + } + } + + fn advance_to_inner(&mut self, n: u32) { + fn advance_iter(iter: &mut container::Iter<'_>, n: u32) -> u64 { + let mut items_skipped = 0; + while let Some(next) = iter.peek() { + if next < n { + iter.next(); + items_skipped += 1; + } else { + return items_skipped; + } + } + items_skipped + } + let (key, _) = util::split(n); + if let Some(index) = self.find_container(key) { + self.drain_containers_until(index); + let container = self.pop_container_front().expect("bug!"); + let mut iter = container.into_iter(); + self.dec_size_hint(advance_iter(&mut iter, n)); + *self.iter_front_mut() = iter; + } else { + // there are no containers with given key. Look in iter_front and iter_back. + if self.iter_front_mut().peek().map(|n| util::split(n).0) == Some(key) { + let skipped = advance_iter(self.iter_front_mut(), n); + self.dec_size_hint(skipped); + return; + } + if self + .iter_back_mut() + .as_mut() + .and_then(|i| i.peek().filter(|n| util::split(*n).0 == key)) + .is_some() + { + let mut iter_back = None; + std::mem::swap(&mut iter_back, self.iter_back_mut()); + let mut iter_back = iter_back.expect("bug!"); + advance_iter(&mut iter_back, n); + self.set_size_hint(iter_back.size_hint().0 as u64); + *self.iter_front_mut() = iter_back; + return; + } + self.clear_containers(); + *self.iter_front_mut() = Self::empty_inner_iter(); + *self.iter_back_mut() = None; + self.set_size_hint(0); + } + } + + #[inline] + fn fold_inner(self, init: B, f: F) -> B + where + F: FnMut(B, u32) -> B, + Self: Sized, + { + let (iter_front, iter_back, containers) = self.decompose(); + if let Some(iter_back) = iter_back { + iter_front.chain(containers.into_iter().flatten()).chain(iter_back).fold(init, f) + } else { + iter_front.chain(containers.into_iter().flatten()).fold(init, f) + } + } + + #[inline] + fn rfold_inner(self, init: Acc, f: Fold) -> Acc + where + Fold: FnMut(Acc, u32) -> Acc, + Self: Sized, + { + let (iter_front, iter_back, containers) = self.decompose(); + if let Some(iter_back) = iter_back { + iter_front.chain(containers.into_iter().flatten()).chain(iter_back).rfold(init, f) + } else { + iter_front.chain(containers.into_iter().flatten()).rfold(init, f) + } + } + + #[inline] + fn advance_container(&mut self) -> Option { + if let Some(container) = self.pop_container_front() { + let front_size_hint = self.iter_front_mut().size_hint().0 as u64; + self.dec_size_hint(front_size_hint); + let result = container.as_ref().key; + *self.iter_front_mut() = container.into_iter(); + Some(result) + } else if self.iter_back_mut().is_some() { + let mut iter_back = None; + core::mem::swap(&mut iter_back, self.iter_back_mut()); + *self.iter_front_mut() = iter_back.expect("bug!"); + let size_hint = self.iter_front_mut().size_hint().0 as u64; + self.set_size_hint(size_hint); + if let Some(v) = self.iter_front_mut().peek() { + let (key, _) = util::split(v); + Some(key) + } else { + None + } + } else { + None + } + } + + #[inline] + fn advance_container_back(&mut self) -> Option { + if let Some(container) = self.pop_container_back() { + let result = container.as_ref().key; + *self.iter_back_mut() = Some(container.into_iter()); + Some(result) + } else if self.iter_front_mut().peek().is_some() { + let mut iter_front = Self::empty_inner_iter(); + core::mem::swap(&mut iter_front, self.iter_front_mut()); + *self.iter_back_mut() = Some(iter_front); + + if let Some(v) = self.iter_back_mut().as_mut().and_then(|i| i.peek()) { + let (key, _) = util::split(v); + Some(key) + } else { + None + } + } else { + None + } + } + } + + impl IterInternal<'static> for IntoIter { + type Container = Container; + type ContainerIterator = alloc::collections::vec_deque::IntoIter; + type IntoContainerIterator = alloc::collections::vec_deque::IntoIter; + + #[inline] + fn pop_container_front(&mut self) -> Option { + self.containers.pop_front() + } + + #[inline] + fn pop_container_back(&mut self) -> Option { + self.containers.pop_back() + } + + #[inline] + fn drain_containers_until(&mut self, index: usize) { + let removed_elements = + self.containers.drain(0..index).map(|container| container.len()).sum(); + self.size_hint = self.size_hint.saturating_sub(removed_elements); + } + + #[inline] + fn clear_containers(&mut self) { + let removed_elements = self.containers.iter().map(|container| container.len()).sum(); + self.size_hint = self.size_hint.saturating_sub(removed_elements); + self.containers.clear(); + } + + #[inline] + fn find_container(&self, key: u16) -> Option { + self.containers.binary_search_by_key(&key, |container| container.key).ok() + } + + #[inline] + fn iter_front_mut(&mut self) -> &mut container::Iter<'static> { + &mut self.iter_front + } + + #[inline] + fn iter_back_mut(&mut self) -> &mut Option> { + &mut self.iter_back + } + + #[inline] + fn dec_size_hint(&mut self, n: u64) { + self.size_hint = self.size_hint.saturating_sub(n); + } + + fn set_size_hint(&mut self, n: u64) { + self.size_hint = n; + } + + fn empty_inner_iter() -> container::Iter<'static> { + container::Iter::empty() + } + + fn decompose( + self, + ) -> (container::Iter<'static>, Option>, Self::IntoContainerIterator) + { + (self.iter_front, self.iter_back, self.containers.into_iter()) + } + } + + impl<'a> IterInternal<'a> for Iter<'a> { + type Container = &'a Container; + type ContainerIterator = slice::Iter<'a, Container>; + + type IntoContainerIterator = slice::Iter<'a, Container>; + + #[inline] + fn pop_container_front(&mut self) -> Option { + if let Some((first, rest)) = self.containers.split_first() { + self.containers = rest; + Some(first) + } else { + None + } + } + + #[inline] + fn pop_container_back(&mut self) -> Option { + if let Some((last, rest)) = self.containers.split_last() { + self.containers = rest; + Some(last) + } else { + None + } + } + + #[inline] + fn drain_containers_until(&mut self, index: usize) { + let removed_elements = + self.containers[..index].iter().map(|container| container.len()).sum(); + self.size_hint = self.size_hint.saturating_sub(removed_elements); + self.containers = &self.containers[index..] + } + + #[inline] + fn clear_containers(&mut self) { + let removed_elements = self.containers.iter().map(|container| container.len()).sum(); + self.size_hint = self.size_hint.saturating_sub(removed_elements); + self.containers = &[]; + } + + #[inline] + fn find_container(&self, key: u16) -> Option { + self.containers.binary_search_by_key(&key, |container| container.key).ok() + } + + #[inline] + fn iter_front_mut(&mut self) -> &mut container::Iter<'a> { + &mut self.iter_front + } + + #[inline] + fn iter_back_mut(&mut self) -> &mut Option> { + &mut self.iter_back + } + + #[inline] + fn dec_size_hint(&mut self, n: u64) { + self.size_hint = self.size_hint.saturating_sub(n); + } + + fn set_size_hint(&mut self, n: u64) { + self.size_hint = n; + } + + fn empty_inner_iter() -> container::Iter<'static> { + container::Iter::empty() + } + + fn decompose( + self, + ) -> (container::Iter<'a>, Option>, Self::IntoContainerIterator) + { + (self.iter_front, self.iter_back, self.containers.iter()) + } + } +} diff --git a/roaring/src/bitmap/store/bitmap_store.rs b/roaring/src/bitmap/store/bitmap_store.rs index f349a2aa..b74af8a7 100644 --- a/roaring/src/bitmap/store/bitmap_store.rs +++ b/roaring/src/bitmap/store/bitmap_store.rs @@ -421,6 +421,28 @@ impl> BitmapIter { bits, } } + + pub fn peek(&self) -> Option { + let mut key = self.key; + let mut value = self.value; + loop { + if value == 0 { + key += 1; + let cmp = self.key.cmp(&self.key_back); + // Match arms can be reordered, this ordering is perf sensitive + value = if cmp == Ordering::Less { + unsafe { *self.bits.borrow().get_unchecked(self.key) } + } else if cmp == Ordering::Equal { + self.value_back + } else { + return None; + }; + continue; + } + let index = value.trailing_zeros() as usize; + return Some((64 * key + index) as u16); + } + } } impl> Iterator for BitmapIter { diff --git a/roaring/src/bitmap/store/mod.rs b/roaring/src/bitmap/store/mod.rs index bb0d5822..b0eef942 100644 --- a/roaring/src/bitmap/store/mod.rs +++ b/roaring/src/bitmap/store/mod.rs @@ -25,13 +25,18 @@ pub enum Store { Bitmap(BitmapStore), } -pub enum Iter<'a> { +enum IterInner<'a> { Array(slice::Iter<'a, u16>), Vec(vec::IntoIter), BitmapBorrowed(BitmapIter<&'a [u64; BITMAP_LENGTH]>), BitmapOwned(BitmapIter>), } +pub struct Iter<'a> { + inner: IterInner<'a>, + size_hint: u64, +} + impl Store { pub fn new() -> Store { Store::Array(ArrayStore::new()) @@ -467,8 +472,10 @@ impl<'a> IntoIterator for &'a Store { type IntoIter = Iter<'a>; fn into_iter(self) -> Iter<'a> { match self { - Array(vec) => Iter::Array(vec.iter()), - Bitmap(bits) => Iter::BitmapBorrowed(bits.iter()), + Array(vec) => Iter { inner: IterInner::Array(vec.iter()), size_hint: vec.len() }, + Bitmap(bits) => { + Iter { inner: IterInner::BitmapBorrowed(bits.iter()), size_hint: bits.len() } + } } } } @@ -478,8 +485,14 @@ impl IntoIterator for Store { type IntoIter = Iter<'static>; fn into_iter(self) -> Iter<'static> { match self { - Array(vec) => Iter::Vec(vec.into_iter()), - Bitmap(bits) => Iter::BitmapOwned(bits.into_iter()), + Array(vec) => { + let size_hint = vec.len(); + Iter { inner: IterInner::Vec(vec.into_iter()), size_hint } + } + Bitmap(bits) => { + let size_hint = bits.len(); + Iter { inner: IterInner::BitmapOwned(bits.into_iter()), size_hint } + } } } } @@ -497,26 +510,46 @@ impl PartialEq for Store { } } -impl<'a> Iterator for Iter<'a> { +impl Iter<'_> { + pub fn peek(&mut self) -> Option { + match &self.inner { + IterInner::Array(inner) => inner.as_slice().first().cloned(), + IterInner::Vec(inner) => inner.as_slice().first().cloned(), + IterInner::BitmapBorrowed(inner) => inner.peek(), + IterInner::BitmapOwned(inner) => inner.peek(), + } + } + + pub fn empty() -> Self { + Self { inner: IterInner::Array([].iter()), size_hint: 0 } + } +} +impl Iterator for Iter<'_> { type Item = u16; fn next(&mut self) -> Option { - match self { - Iter::Array(inner) => inner.next().cloned(), - Iter::Vec(inner) => inner.next(), - Iter::BitmapBorrowed(inner) => inner.next(), - Iter::BitmapOwned(inner) => inner.next(), + self.size_hint = self.size_hint.saturating_sub(1); + match &mut self.inner { + IterInner::Array(inner) => inner.next().cloned(), + IterInner::Vec(inner) => inner.next(), + IterInner::BitmapBorrowed(inner) => inner.next(), + IterInner::BitmapOwned(inner) => inner.next(), } } + + fn size_hint(&self) -> (usize, Option) { + (self.size_hint as usize, Some(self.size_hint as usize)) + } } impl DoubleEndedIterator for Iter<'_> { fn next_back(&mut self) -> Option { - match self { - Iter::Array(inner) => inner.next_back().cloned(), - Iter::Vec(inner) => inner.next_back(), - Iter::BitmapBorrowed(inner) => inner.next_back(), - Iter::BitmapOwned(inner) => inner.next_back(), + self.size_hint = self.size_hint.saturating_sub(1); + match &mut self.inner { + IterInner::Array(inner) => inner.next_back().cloned(), + IterInner::Vec(inner) => inner.next_back(), + IterInner::BitmapBorrowed(inner) => inner.next_back(), + IterInner::BitmapOwned(inner) => inner.next_back(), } } } diff --git a/roaring/src/lib.rs b/roaring/src/lib.rs index b44c19c2..b4cbf5a5 100644 --- a/roaring/src/lib.rs +++ b/roaring/src/lib.rs @@ -19,6 +19,7 @@ extern crate byteorder; #[macro_use] extern crate alloc; +extern crate core; use core::fmt; diff --git a/roaring/src/treemap/iter.rs b/roaring/src/treemap/iter.rs index 96ccb00d..f8094a37 100644 --- a/roaring/src/treemap/iter.rs +++ b/roaring/src/treemap/iter.rs @@ -11,7 +11,7 @@ struct To64Iter<'a> { inner: Iter32<'a>, } -impl<'a> Iterator for To64Iter<'a> { +impl Iterator for To64Iter<'_> { type Item = u64; fn next(&mut self) -> Option { self.inner.next().map(|n| util::join(self.hi, n)) @@ -109,7 +109,7 @@ pub struct IntoIter { size_hint: u64, } -impl<'a> Iter<'a> { +impl Iter<'_> { fn new(map: &BTreeMap) -> Iter { let size_hint: u64 = map.iter().map(|(_, r)| r.len()).sum(); let i = map.iter().flat_map(to64iter as _); @@ -125,7 +125,7 @@ impl IntoIter { } } -impl<'a> Iterator for Iter<'a> { +impl Iterator for Iter<'_> { type Item = u64; fn next(&mut self) -> Option { diff --git a/roaring/tests/iter_advance_to.rs b/roaring/tests/iter_advance_to.rs new file mode 100644 index 00000000..07e55a74 --- /dev/null +++ b/roaring/tests/iter_advance_to.rs @@ -0,0 +1,94 @@ +use roaring::RoaringBitmap; + +#[test] +fn iter_basic() { + let bm = RoaringBitmap::from([1, 2, 3, 4, 11, 12, 13, 14]); + let mut i = bm.iter(); + i.advance_to(10); + for n in 11..=14 { + assert_eq!(i.next(), Some(n)) + } + assert_eq!(i.next(), None); +} + +#[test] +fn iter_advance_past_end() { + let bm = RoaringBitmap::from([1, 2, 3, 4, 11, 12, 13, 14]); + let mut i = bm.iter(); + i.advance_to(15); + assert_eq!(i.next(), None); + assert_eq!(i.size_hint(), (0, Some(0))); +} + +#[test] +fn iter_multi_container() { + let bm = RoaringBitmap::from([1, 2, 3, 100000, 100001]); + let mut i = bm.iter(); + i.advance_to(3); + assert_eq!(i.size_hint(), (3, Some(3))); + assert_eq!(i.next(), Some(3)); + assert_eq!(i.size_hint(), (2, Some(2))); + assert_eq!(i.next(), Some(100000)); + assert_eq!(i.size_hint(), (1, Some(1))); + assert_eq!(i.next(), Some(100001)); + assert_eq!(i.size_hint(), (0, Some(0))); + assert_eq!(i.next(), None); + assert_eq!(i.size_hint(), (0, Some(0))); +} + +#[test] +fn iter_empty() { + let bm = RoaringBitmap::new(); + let mut i = bm.iter(); + i.advance_to(31337); + assert_eq!(i.size_hint(), (0, Some(0))); + assert_eq!(i.next(), None) +} + +#[test] +fn into_iter_basic() { + let bm = RoaringBitmap::from([1, 2, 3, 4, 11, 12, 13, 14]); + let mut i = bm.into_iter(); + i.advance_to(10); + let mut expected_size_hint = 4; + assert_eq!(i.size_hint(), (expected_size_hint, Some(expected_size_hint))); + for n in 11..=14 { + assert_eq!(i.next(), Some(n)); + expected_size_hint -= 1; + assert_eq!(i.size_hint(), (expected_size_hint, Some(expected_size_hint))); + } + assert_eq!(i.next(), None); +} + +#[test] +fn into_iter_multi_container() { + let bm = RoaringBitmap::from([1, 2, 3, 100000, 100001]); + let mut i = bm.into_iter(); + i.advance_to(3); + assert_eq!(i.size_hint(), (3, Some(3))); + assert_eq!(i.next(), Some(3)); + assert_eq!(i.next(), Some(100000)); + assert_eq!(i.next(), Some(100001)); + assert_eq!(i.next(), None); +} + +#[test] +fn into_iter_empty() { + let bm = RoaringBitmap::new(); + let mut i = bm.into_iter(); + i.advance_to(31337); + assert_eq!(i.size_hint(), (0, Some(0))); + assert_eq!(i.next(), None) +} + +#[test] +fn advance_to_with_tail_iter() { + let bm = RoaringBitmap::from([1, 2, 3, 100000, 100001]); + let mut i = bm.iter(); + i.next_back(); + i.advance_to(100000); + assert_eq!(i.size_hint(), (1, Some(1))); + assert_eq!(i.next(), Some(100000)); + assert_eq!(i.size_hint(), (0, Some(0))); + assert_eq!(i.next(), None); +}