use crate::bit_iterator::BitSliceIterator;
use crate::contains_nulls;
use std::mem::size_of;
use crate::data::ArrayData;
use super::utils::equal_len;
pub(crate) const NULL_SLICES_SELECTIVITY_THRESHOLD: f64 = 0.4;
pub(super) fn primitive_equal<T>(
lhs: &ArrayData,
rhs: &ArrayData,
lhs_start: usize,
rhs_start: usize,
len: usize,
) -> bool {
let byte_width = size_of::<T>();
let lhs_values = &lhs.buffers()[0].as_slice()[lhs.offset() * byte_width..];
let rhs_values = &rhs.buffers()[0].as_slice()[rhs.offset() * byte_width..];
if !contains_nulls(lhs.nulls(), lhs_start, len) {
equal_len(
lhs_values,
rhs_values,
lhs_start * byte_width,
rhs_start * byte_width,
len * byte_width,
)
} else {
let selectivity_frac = lhs.null_count() as f64 / lhs.len() as f64;
if selectivity_frac >= NULL_SLICES_SELECTIVITY_THRESHOLD {
let lhs_nulls = lhs.nulls().unwrap();
let rhs_nulls = rhs.nulls().unwrap();
(0..len).all(|i| {
let lhs_pos = lhs_start + i;
let rhs_pos = rhs_start + i;
let lhs_is_null = lhs_nulls.is_null(lhs_pos);
let rhs_is_null = rhs_nulls.is_null(rhs_pos);
lhs_is_null
|| (lhs_is_null == rhs_is_null)
&& equal_len(
lhs_values,
rhs_values,
lhs_pos * byte_width,
rhs_pos * byte_width,
byte_width, )
})
} else {
let lhs_nulls = lhs.nulls().unwrap();
let lhs_slices_iter =
BitSliceIterator::new(lhs_nulls.validity(), lhs_start + lhs_nulls.offset(), len);
let rhs_nulls = rhs.nulls().unwrap();
let rhs_slices_iter =
BitSliceIterator::new(rhs_nulls.validity(), rhs_start + rhs_nulls.offset(), len);
lhs_slices_iter
.zip(rhs_slices_iter)
.all(|((l_start, l_end), (r_start, r_end))| {
l_start == r_start
&& l_end == r_end
&& equal_len(
lhs_values,
rhs_values,
(lhs_start + l_start) * byte_width,
(rhs_start + r_start) * byte_width,
(l_end - l_start) * byte_width,
)
})
}
}
}