Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fuzz/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/arbitrary_ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ impl MutableBitmapOperation {
if should_push {
x.add(n);
}
assert_eq!(should_push, y.push(n));
assert_eq!(should_push, y.try_push(n).is_ok());
}
MutableBitmapOperation::Remove(Num(n)) => {
let expected = x.remove_checked(n);
Expand Down
2 changes: 1 addition & 1 deletion roaring/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "roaring"
version = "0.11.3"
version = "0.11.4"
# When changing this value don't forget to change the MSRV test in `.github/workflows/test.yml`!!
rust-version = "1.90.0"
authors = ["Wim Looman <wim@nemo157.com>", "Kerollmops <kero@meilisearch.com>"]
Expand Down
53 changes: 37 additions & 16 deletions roaring/src/bitmap/store/interval_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,23 +862,23 @@ impl<I: SliceIterator<Interval>> Iterator for RunIter<I> {
self.backward_offset = 0;
return None;
}
if let Some(skip) = n.checked_sub(1) {
let mut to_skip = skip as u64;
loop {
let full_first_interval_len = self.intervals.as_slice().first()?.run_len();
let consumed_len = u64::from(self.forward_offset)
+ if self.intervals.as_slice().len() == 1 {
u64::from(self.backward_offset)
} else {
0
};
let to_remove = (full_first_interval_len - consumed_len).min(to_skip);
to_skip -= to_remove;
self.forward_offset += to_remove as u16;
let mut to_skip = n as u64;
loop {
let full_first_interval_len = self.intervals.as_slice().first()?.run_len();
let consumed_len = u64::from(self.forward_offset)
+ if self.intervals.as_slice().len() == 1 {
u64::from(self.backward_offset)
} else {
0
};
let to_remove = (full_first_interval_len - consumed_len).min(to_skip);
to_skip -= to_remove;
self.forward_offset += to_remove as u16;
if consumed_len + to_remove >= full_first_interval_len {
self.move_next();
if to_skip == 0 {
break;
}
}
if to_skip == 0 {
break;
}
}
self.next()
Expand Down Expand Up @@ -2477,6 +2477,27 @@ mod tests {
assert_eq!(iter.nth(u16::MAX as usize), None);
}

// Regression test for https://github.com/RoaringBitmap/roaring-rs/issues/352
#[test]
#[allow(clippy::iter_nth_zero)]
fn iter_nth_single_element_intervals() {
// A RunStore made of single-element intervals {0,0}, {2,2}, ..., {246,246}.
// nth(123) must return 246 (index 123 in the sequence 0, 2, 4, ...).
// The buggy code returned 244 (index 122).
let intervals: alloc::vec::Vec<_> =
(0u16..=246).step_by(2).map(|v| Interval::new_unchecked(v, v)).collect();
let interval_store = IntervalStore(intervals);

let mut iter = interval_store.iter();
assert_eq!(iter.nth(0), Some(0));

let mut iter = interval_store.iter();
assert_eq!(iter.nth(1), Some(2));

let mut iter = interval_store.iter();
assert_eq!(iter.nth(123), Some(246));
}

#[test]
fn iter_advance_to() {
let interval_store = IntervalStore(alloc::vec![
Expand Down
Loading