use arrow_array::*;
use arrow_buffer::bit_util::ceil;
use arrow_buffer::buffer::{
bitwise_bin_op_helper, bitwise_quaternary_op_helper, buffer_bin_and, buffer_bin_or,
buffer_unary_not,
};
use arrow_buffer::{Buffer, MutableBuffer};
use arrow_data::bit_mask::combine_option_bitmap;
use arrow_data::ArrayData;
use arrow_schema::{ArrowError, DataType};
pub(crate) fn build_null_buffer_for_and_kleene(
left_data: &ArrayData,
left_offset: usize,
right_data: &ArrayData,
right_offset: usize,
len_in_bits: usize,
) -> Option<Buffer> {
let left_buffer = &left_data.buffers()[0];
let right_buffer = &right_data.buffers()[0];
let left_null_buffer = left_data.null_buffer();
let right_null_buffer = right_data.null_buffer();
match (left_null_buffer, right_null_buffer) {
(None, None) => None,
(Some(left_null_buffer), None) => {
Some(bitwise_bin_op_helper(
left_null_buffer,
left_offset,
right_buffer,
right_offset,
len_in_bits,
|a, b| a | !b,
))
}
(None, Some(right_null_buffer)) => {
Some(bitwise_bin_op_helper(
right_null_buffer,
right_offset,
left_buffer,
left_offset,
len_in_bits,
|a, b| a | !b,
))
}
(Some(left_null_buffer), Some(right_null_buffer)) => {
Some(bitwise_quaternary_op_helper(
[
left_null_buffer,
left_buffer,
right_null_buffer,
right_buffer,
],
[left_offset, left_offset, right_offset, right_offset],
len_in_bits,
|a, b, c, d| (a | (c & !d)) & (c | (a & !b)),
))
}
}
}
pub(crate) fn build_null_buffer_for_and_or(
left_data: &ArrayData,
_left_offset: usize,
right_data: &ArrayData,
_right_offset: usize,
len_in_bits: usize,
) -> Option<Buffer> {
combine_option_bitmap(&[left_data, right_data], len_in_bits)
}
pub(crate) fn build_null_buffer_for_or_kleene(
left_data: &ArrayData,
left_offset: usize,
right_data: &ArrayData,
right_offset: usize,
len_in_bits: usize,
) -> Option<Buffer> {
let left_buffer = &left_data.buffers()[0];
let right_buffer = &right_data.buffers()[0];
let left_null_buffer = left_data.null_buffer();
let right_null_buffer = right_data.null_buffer();
match (left_null_buffer, right_null_buffer) {
(None, None) => None,
(Some(left_null_buffer), None) => {
Some(bitwise_bin_op_helper(
left_null_buffer,
left_offset,
right_buffer,
right_offset,
len_in_bits,
|a, b| a | b,
))
}
(None, Some(right_null_buffer)) => {
Some(bitwise_bin_op_helper(
right_null_buffer,
right_offset,
left_buffer,
left_offset,
len_in_bits,
|a, b| a | b,
))
}
(Some(left_null_buffer), Some(right_null_buffer)) => {
Some(bitwise_quaternary_op_helper(
[
left_null_buffer,
left_buffer,
right_null_buffer,
right_buffer,
],
[left_offset, left_offset, right_offset, right_offset],
len_in_bits,
|a, b, c, d| (a | (c & d)) & (c | (a & b)),
))
}
}
}
pub(crate) fn binary_boolean_kernel<F, U>(
left: &BooleanArray,
right: &BooleanArray,
op: F,
null_op: U,
) -> Result<BooleanArray, ArrowError>
where
F: Fn(&Buffer, usize, &Buffer, usize, usize) -> Buffer,
U: Fn(&ArrayData, usize, &ArrayData, usize, usize) -> Option<Buffer>,
{
if left.len() != right.len() {
return Err(ArrowError::ComputeError(
"Cannot perform bitwise operation on arrays of different length".to_string(),
));
}
let len = left.len();
let left_data = left.data_ref();
let right_data = right.data_ref();
let left_buffer = &left_data.buffers()[0];
let right_buffer = &right_data.buffers()[0];
let left_offset = left.offset();
let right_offset = right.offset();
let null_bit_buffer = null_op(left_data, left_offset, right_data, right_offset, len);
let values = op(left_buffer, left_offset, right_buffer, right_offset, len);
let data = unsafe {
ArrayData::new_unchecked(
DataType::Boolean,
len,
None,
null_bit_buffer,
0,
vec![values],
vec![],
)
};
Ok(BooleanArray::from(data))
}
pub fn and(
left: &BooleanArray,
right: &BooleanArray,
) -> Result<BooleanArray, ArrowError> {
binary_boolean_kernel(left, right, buffer_bin_and, build_null_buffer_for_and_or)
}
pub fn and_kleene(
left: &BooleanArray,
right: &BooleanArray,
) -> Result<BooleanArray, ArrowError> {
binary_boolean_kernel(
left,
right,
buffer_bin_and,
build_null_buffer_for_and_kleene,
)
}
pub fn or(left: &BooleanArray, right: &BooleanArray) -> Result<BooleanArray, ArrowError> {
binary_boolean_kernel(left, right, buffer_bin_or, build_null_buffer_for_and_or)
}
pub fn or_kleene(
left: &BooleanArray,
right: &BooleanArray,
) -> Result<BooleanArray, ArrowError> {
binary_boolean_kernel(left, right, buffer_bin_or, build_null_buffer_for_or_kleene)
}
pub fn not(left: &BooleanArray) -> Result<BooleanArray, ArrowError> {
let left_offset = left.offset();
let len = left.len();
let data = left.data_ref();
let null_bit_buffer = data
.null_bitmap()
.as_ref()
.map(|b| b.buffer().bit_slice(left_offset, len));
let values = buffer_unary_not(&data.buffers()[0], left_offset, len);
let data = unsafe {
ArrayData::new_unchecked(
DataType::Boolean,
len,
None,
null_bit_buffer,
0,
vec![values],
vec![],
)
};
Ok(BooleanArray::from(data))
}
pub fn is_null(input: &dyn Array) -> Result<BooleanArray, ArrowError> {
let len = input.len();
let output = match input.data_ref().null_buffer() {
None => {
let len_bytes = ceil(len, 8);
MutableBuffer::from_len_zeroed(len_bytes).into()
}
Some(buffer) => buffer_unary_not(buffer, input.offset(), len),
};
let data = unsafe {
ArrayData::new_unchecked(
DataType::Boolean,
len,
None,
None,
0,
vec![output],
vec![],
)
};
Ok(BooleanArray::from(data))
}
pub fn is_not_null(input: &dyn Array) -> Result<BooleanArray, ArrowError> {
let len = input.len();
let output = match input.data_ref().null_buffer() {
None => {
let len_bytes = ceil(len, 8);
MutableBuffer::new(len_bytes)
.with_bitset(len_bytes, true)
.into()
}
Some(buffer) => buffer.bit_slice(input.offset(), len),
};
let data = unsafe {
ArrayData::new_unchecked(
DataType::Boolean,
len,
None,
None,
0,
vec![output],
vec![],
)
};
Ok(BooleanArray::from(data))
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn test_bool_array_and() {
let a = BooleanArray::from(vec![false, false, true, true]);
let b = BooleanArray::from(vec![false, true, false, true]);
let c = and(&a, &b).unwrap();
let expected = BooleanArray::from(vec![false, false, false, true]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_or() {
let a = BooleanArray::from(vec![false, false, true, true]);
let b = BooleanArray::from(vec![false, true, false, true]);
let c = or(&a, &b).unwrap();
let expected = BooleanArray::from(vec![false, true, true, true]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_or_nulls() {
let a = BooleanArray::from(vec![
None,
None,
None,
Some(false),
Some(false),
Some(false),
Some(true),
Some(true),
Some(true),
]);
let b = BooleanArray::from(vec![
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
]);
let c = or(&a, &b).unwrap();
let expected = BooleanArray::from(vec![
None,
None,
None,
None,
Some(false),
Some(true),
None,
Some(true),
Some(true),
]);
assert_eq!(c, expected);
}
#[test]
fn test_boolean_array_kleene_no_remainder() {
let n = 1024;
let a = BooleanArray::from(vec![true; n]);
let b = BooleanArray::from(vec![None; n]);
let result = or_kleene(&a, &b).unwrap();
assert_eq!(result, a);
}
#[test]
fn test_bool_array_and_kleene_nulls() {
let a = BooleanArray::from(vec![
None,
None,
None,
Some(false),
Some(false),
Some(false),
Some(true),
Some(true),
Some(true),
]);
let b = BooleanArray::from(vec![
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
]);
let c = and_kleene(&a, &b).unwrap();
let expected = BooleanArray::from(vec![
None,
Some(false),
None,
Some(false),
Some(false),
Some(false),
None,
Some(false),
Some(true),
]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_or_kleene_nulls() {
let a = BooleanArray::from(vec![
None,
None,
None,
Some(false),
Some(false),
Some(false),
Some(true),
Some(true),
Some(true),
]);
let b = BooleanArray::from(vec![
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
]);
let c = or_kleene(&a, &b).unwrap();
let expected = BooleanArray::from(vec![
None,
None,
Some(true),
None,
Some(false),
Some(true),
Some(true),
Some(true),
Some(true),
]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_or_kleene_right_sided_nulls() {
let a = BooleanArray::from(vec![false, false, false, true, true, true]);
assert!(a.data_ref().null_bitmap().is_none());
let b = BooleanArray::from(vec![
Some(true),
Some(false),
None,
Some(true),
Some(false),
None,
]);
assert!(b.data_ref().null_bitmap().is_some());
let c = or_kleene(&a, &b).unwrap();
let expected = BooleanArray::from(vec![
Some(true),
Some(false),
None,
Some(true),
Some(true),
Some(true),
]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_or_kleene_left_sided_nulls() {
let a = BooleanArray::from(vec![
Some(true),
Some(false),
None,
Some(true),
Some(false),
None,
]);
assert!(a.data_ref().null_bitmap().is_some());
let b = BooleanArray::from(vec![false, false, false, true, true, true]);
assert!(b.data_ref().null_bitmap().is_none());
let c = or_kleene(&a, &b).unwrap();
let expected = BooleanArray::from(vec![
Some(true),
Some(false),
None,
Some(true),
Some(true),
Some(true),
]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_not() {
let a = BooleanArray::from(vec![false, true]);
let c = not(&a).unwrap();
let expected = BooleanArray::from(vec![true, false]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_not_sliced() {
let a = BooleanArray::from(vec![None, Some(true), Some(false), None, Some(true)]);
let a = a.slice(1, 4);
let a = a.as_any().downcast_ref::<BooleanArray>().unwrap();
let c = not(a).unwrap();
let expected =
BooleanArray::from(vec![Some(false), Some(true), None, Some(false)]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_and_nulls() {
let a = BooleanArray::from(vec![
None,
None,
None,
Some(false),
Some(false),
Some(false),
Some(true),
Some(true),
Some(true),
]);
let b = BooleanArray::from(vec![
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
None,
Some(false),
Some(true),
]);
let c = and(&a, &b).unwrap();
let expected = BooleanArray::from(vec![
None,
None,
None,
None,
Some(false),
Some(false),
None,
Some(false),
Some(true),
]);
assert_eq!(c, expected);
}
#[test]
fn test_bool_array_and_sliced_same_offset() {
let a = BooleanArray::from(vec![
false, false, false, false, false, false, false, false, false, false, true,
true,
]);
let b = BooleanArray::from(vec![
false, false, false, false, false, false, false, false, false, true, false,
true,
]);
let a = a.slice(8, 4);
let a = a.as_any().downcast_ref::<BooleanArray>().unwrap();
let b = b.slice(8, 4);
let b = b.as_any().downcast_ref::<BooleanArray>().unwrap();
let c = and(a, b).unwrap();
let expected = BooleanArray::from(vec![false, false, false, true]);
assert_eq!(expected, c);
}
#[test]
fn test_bool_array_and_sliced_same_offset_mod8() {
let a = BooleanArray::from(vec![
false, false, true, true, false, false, false, false, false, false, false,
false,
]);
let b = BooleanArray::from(vec![
false, false, false, false, false, false, false, false, false, true, false,
true,
]);
let a = a.slice(0, 4);
let a = a.as_any().downcast_ref::<BooleanArray>().unwrap();
let b = b.slice(8, 4);
let b = b.as_any().downcast_ref::<BooleanArray>().unwrap();
let c = and(a, b).unwrap();
let expected = BooleanArray::from(vec![false, false, false, true]);
assert_eq!(expected, c);
}
#[test]
fn test_bool_array_and_sliced_offset1() {
let a = BooleanArray::from(vec![
false, false, false, false, false, false, false, false, false, false, true,
true,
]);
let b = BooleanArray::from(vec![false, true, false, true]);
let a = a.slice(8, 4);
let a = a.as_any().downcast_ref::<BooleanArray>().unwrap();
let c = and(a, &b).unwrap();
let expected = BooleanArray::from(vec![false, false, false, true]);
assert_eq!(expected, c);
}
#[test]
fn test_bool_array_and_sliced_offset2() {
let a = BooleanArray::from(vec![false, false, true, true]);
let b = BooleanArray::from(vec![
false, false, false, false, false, false, false, false, false, true, false,
true,
]);
let b = b.slice(8, 4);
let b = b.as_any().downcast_ref::<BooleanArray>().unwrap();
let c = and(&a, b).unwrap();
let expected = BooleanArray::from(vec![false, false, false, true]);
assert_eq!(expected, c);
}
#[test]
fn test_bool_array_and_nulls_offset() {
let a = BooleanArray::from(vec![None, Some(false), Some(true), None, Some(true)]);
let a = a.slice(1, 4);
let a = a.as_any().downcast_ref::<BooleanArray>().unwrap();
let b = BooleanArray::from(vec![
None,
None,
Some(true),
Some(false),
Some(true),
Some(true),
]);
let b = b.slice(2, 4);
let b = b.as_any().downcast_ref::<BooleanArray>().unwrap();
let c = and(a, b).unwrap();
let expected =
BooleanArray::from(vec![Some(false), Some(false), None, Some(true)]);
assert_eq!(expected, c);
}
#[test]
fn test_nonnull_array_is_null() {
let a: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
let res = is_null(a.as_ref()).unwrap();
let expected = BooleanArray::from(vec![false, false, false, false]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nonnull_array_with_offset_is_null() {
let a = Int32Array::from(vec![1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1]);
let a = a.slice(8, 4);
let res = is_null(a.as_ref()).unwrap();
let expected = BooleanArray::from(vec![false, false, false, false]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nonnull_array_is_not_null() {
let a = Int32Array::from(vec![1, 2, 3, 4]);
let res = is_not_null(&a).unwrap();
let expected = BooleanArray::from(vec![true, true, true, true]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nonnull_array_with_offset_is_not_null() {
let a = Int32Array::from(vec![1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1]);
let a = a.slice(8, 4);
let res = is_not_null(a.as_ref()).unwrap();
let expected = BooleanArray::from(vec![true, true, true, true]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nullable_array_is_null() {
let a = Int32Array::from(vec![Some(1), None, Some(3), None]);
let res = is_null(&a).unwrap();
let expected = BooleanArray::from(vec![false, true, false, true]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nullable_array_with_offset_is_null() {
let a = Int32Array::from(vec![
None,
None,
None,
None,
None,
None,
None,
None,
Some(1),
None,
Some(2),
None,
Some(3),
Some(4),
None,
None,
]);
let a = a.slice(8, 4);
let res = is_null(a.as_ref()).unwrap();
let expected = BooleanArray::from(vec![false, true, false, true]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nullable_array_is_not_null() {
let a = Int32Array::from(vec![Some(1), None, Some(3), None]);
let res = is_not_null(&a).unwrap();
let expected = BooleanArray::from(vec![true, false, true, false]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
#[test]
fn test_nullable_array_with_offset_is_not_null() {
let a = Int32Array::from(vec![
None,
None,
None,
None,
None,
None,
None,
None,
Some(1),
None,
Some(2),
None,
Some(3),
Some(4),
None,
None,
]);
let a = a.slice(8, 4);
let res = is_not_null(a.as_ref()).unwrap();
let expected = BooleanArray::from(vec![true, false, true, false]);
assert_eq!(expected, res);
assert_eq!(None, res.data_ref().null_bitmap());
}
}