Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Fixed error in chunked_mut bitmap #1081

Merged
merged 1 commit into from
Jun 18, 2022
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
13 changes: 7 additions & 6 deletions src/bitmap/utils/chunk_iterator/chunks_exact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ pub struct BitChunksExact<'a, T: BitChunk> {
impl<'a, T: BitChunk> BitChunksExact<'a, T> {
/// Creates a new [`BitChunksExact`].
#[inline]
pub fn new(slice: &'a [u8], len: usize) -> Self {
assert!(len <= slice.len() * 8);
pub fn new(bitmap: &'a [u8], length: usize) -> Self {
assert!(length <= bitmap.len() * 8);
let size_of = std::mem::size_of::<T>();

let split = (len / 8 / size_of) * size_of;
let chunks = &slice[..split];
let remainder = &slice[split..];
let remainder_len = len - chunks.len() * 8;
let bitmap = &bitmap[..length.saturating_add(7) / 8];

let split = (length / 8 / size_of) * size_of;
let (chunks, remainder) = bitmap.split_at(split);
let remainder_len = length - chunks.len() * 8;
let iter = chunks.chunks_exact(size_of);

Self {
Expand Down
3 changes: 3 additions & 0 deletions src/bitmap/utils/chunks_exact_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ impl<'a, T: BitChunk> BitChunksExactMut<'a, T> {
/// Returns a new [`BitChunksExactMut`]
#[inline]
pub fn new(bitmap: &'a mut [u8], length: usize) -> Self {
assert!(length <= bitmap.len() * 8);
let size_of = std::mem::size_of::<T>();

let bitmap = &mut bitmap[..length.saturating_add(7) / 8];

let split = (length / 8 / size_of) * size_of;
let (chunks, remainder) = bitmap.split_at_mut(split);
let remainder_len = length - chunks.len() * 8;
Expand Down
55 changes: 25 additions & 30 deletions src/compute/arity_assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,42 +46,37 @@ where
// new buffer, that is benchmarked to be ~2x faster than first memcpy and assign in place
// for the validity bits it can be much faster as we might need to iterate all bits if the
// bitmap has an offset.
match rhs.validity() {
None => {}
Some(rhs) => {
if lhs.validity().is_none() {
*lhs = lhs.with_validity(Some(rhs.clone()))
} else {
lhs.apply_validity(|bitmap| {
// we need to take ownership for the `into_mut` call, but leave the `&mut` lhs intact
// so that we can later assign the result to out `&mut bitmap`
let owned_lhs = std::mem::take(bitmap);
if let Some(rhs) = rhs.validity() {
if lhs.validity().is_none() {
*lhs = lhs.with_validity(Some(rhs.clone()))
} else {
lhs.apply_validity(|bitmap| {
// we need to take ownership for the `into_mut` call, but leave the `&mut` lhs intact
// so that we can later assign the result to out `&mut bitmap`
let owned_lhs = std::mem::take(bitmap);

match owned_lhs.into_mut() {
// we take alloc and write to new buffer
Either::Left(immutable) => {
// we allocate a new bitmap because that is a lot faster
// than doing the memcpy or the potential iteration of bits if
// we are dealing with an offset
let new = &immutable & rhs;
*bitmap = new;
}
// we can mutate in place, happy days.
Either::Right(mut mutable) => {
let mut mutable_ref = &mut mutable;
mutable_ref &= rhs;
*bitmap = mutable.into()
}
*bitmap = match owned_lhs.into_mut() {
// we take alloc and write to new buffer
Either::Left(immutable) => {
// we allocate a new bitmap
&immutable & rhs
}
});
}
// we can mutate in place, happy days.
Either::Right(mut mutable) => {
let mut mutable_ref = &mut mutable;
mutable_ref &= rhs;
mutable.into()
}
}
});
}
}

// we need to take ownership for the `into_mut` call, but leave the `&mut` lhs intact
// so that we can later assign the result to out `&mut lhs`
let owned_lhs = std::mem::take(lhs);

match owned_lhs.into_mut() {
*lhs = match owned_lhs.into_mut() {
// we take alloc and write to new buffer
Either::Left(mut immutable) => {
let values = immutable
Expand All @@ -91,7 +86,7 @@ where
.map(|(l, r)| op(*l, *r))
.collect::<Vec<_>>();
immutable.set_values(values.into());
*lhs = immutable;
immutable
}
// we can mutate in place
Either::Right(mut mutable) => {
Expand All @@ -100,7 +95,7 @@ where
.zip(rhs.values().iter())
.for_each(|(l, r)| *l = op(*l, *r))
});
*lhs = mutable.into()
mutable.into()
}
}
}
19 changes: 19 additions & 0 deletions tests/it/bitmap/assign_ops.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use proptest::prelude::*;

use arrow2::bitmap::{binary_assign, unary_assign, Bitmap, MutableBitmap};

use crate::bitmap::bitmap_strategy;

#[test]
fn basics() {
let mut b = MutableBitmap::from_iter(std::iter::repeat(true).take(10));
Expand Down Expand Up @@ -58,3 +62,18 @@ fn fast_paths() {
let b = b | &c;
assert_eq!(b, MutableBitmap::from_iter([true, false]));
}

proptest! {
/// Asserts that !bitmap equals all bits flipped
#[test]
#[cfg_attr(miri, ignore)] // miri and proptest do not work well :(
fn not(b in bitmap_strategy()) {
let not_b: MutableBitmap = b.iter().map(|x| !x).collect();

let mut b = b.make_mut();

unary_assign(&mut b, |x: u8| !x);

assert_eq!(b, not_b);
}
}
2 changes: 1 addition & 1 deletion tests/it/bitmap/utils/bit_chunks_exact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ fn remainder_u16() {
);
assert_eq!(iter.next(), Some(511));
assert_eq!(iter.next(), None);
assert_eq!(iter.remainder(), 0b1101_1011_0000_0001u16);
assert_eq!(iter.remainder(), 1u16);
}