diff --git a/benches/bitmap_ops.rs b/benches/bitmap_ops.rs index a2884799923..8a606fb8d36 100644 --- a/benches/bitmap_ops.rs +++ b/benches/bitmap_ops.rs @@ -18,6 +18,33 @@ fn add_benchmark(c: &mut Criterion) { assert!(r.null_count() > 0); }) }); + + let offset = ((size as f64) * 0.1) as usize; + let len = ((size as f64) * 0.85) as usize; + + c.bench_function( + &format!("bitmap count zeros 85% slice 2^{}", log2_size), + |b| { + b.iter(|| { + let r = bitmap.clone().slice(offset, len); + assert!(r.null_count() > 0); + }) + }, + ); + + let offset = ((size as f64) * 0.2) as usize; + let len = ((size as f64) * 0.51) as usize; + + c.bench_function( + &format!("bitmap count zeros 51% slice 2^{}", log2_size), + |b| { + b.iter(|| { + let r = bitmap.clone().slice(offset, len); + assert!(r.null_count() > 0); + }) + }, + ); + let bitmap1 = bitmap.clone().slice(1, size - 1); c.bench_function(&format!("bitmap not 2^{}", log2_size), |b| { b.iter(|| { diff --git a/src/bitmap/immutable.rs b/src/bitmap/immutable.rs index 6389c078d36..c2f5e91fd9d 100644 --- a/src/bitmap/immutable.rs +++ b/src/bitmap/immutable.rs @@ -121,9 +121,19 @@ impl Bitmap { /// The caller must ensure that `self.offset + offset + length <= self.len()` #[inline] pub unsafe fn slice_unchecked(mut self, offset: usize, length: usize) -> Self { + // count the smallest chunk + if length < self.length / 2 { + // count the null values in the slice + self.null_count = count_zeros(&self.bytes, offset, length); + } else { + // subtract the null count of the chunks we slice off + let start_end = self.offset + offset + length; + let head_count = count_zeros(&self.bytes, self.offset, offset); + let tail_count = count_zeros(&self.bytes, start_end, self.length - length - offset); + self.null_count -= head_count + tail_count; + } self.offset += offset; self.length = length; - self.null_count = count_zeros(&self.bytes, self.offset, self.length); self }