use fastlanes::BitPacking;
use fastlanes::BitPackingCompare;
use fastlanes::FastLanesComparable;
use fastlanes::untranspose_bits;
use num_traits::AsPrimitive;
use vortex_array::ArrayRef;
use vortex_array::ArrayView;
use vortex_array::ExecutionCtx;
use vortex_array::IntoArray;
use vortex_array::arrays::BoolArray;
use vortex_array::arrays::PrimitiveArray;
use vortex_array::dtype::NativePType;
use vortex_array::dtype::Nullability;
use vortex_array::dtype::PhysicalPType;
use vortex_array::match_each_unsigned_integer_ptype;
use vortex_buffer::BitBufferMut;
use vortex_buffer::BufferMut;
use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use super::stream_predicate::stream_predicate;
use crate::BitPacked;
use crate::BitPackedArrayExt;
use crate::unpack_iter::BitPacked as BitPackedIter;
const CHUNK_SIZE: usize = 1024;
const U64_BITS: usize = u64::BITS as usize;
const WORDS_PER_CHUNK: usize = CHUNK_SIZE / U64_BITS;
pub(super) fn stream_compare_fused<T, F>(
array: ArrayView<'_, BitPacked>,
rhs: T,
nullability: Nullability,
cmp: F,
ctx: &mut ExecutionCtx,
) -> VortexResult<ArrayRef>
where
T: NativePType
+ BitPackedIter
+ FastLanesComparable<Bitpacked = <T as PhysicalPType>::Physical>,
<T as PhysicalPType>::Physical: BitPacking + NativePType + BitPackingCompare,
F: Fn(T, T) -> bool + Copy,
{
let len = array.len();
let bit_width = array.bit_width() as usize;
let offset = array.offset() as usize;
if len == 0 || bit_width == 0 {
return stream_predicate::<T, _>(array, nullability, move |v| cmp(v, rhs), ctx);
}
let num_chunks = (offset + len).div_ceil(CHUNK_SIZE);
let mut words: BufferMut<u64> = BufferMut::zeroed(num_chunks * WORDS_PER_CHUNK);
let chunks = array.unpacked_chunks::<T>()?;
{
let words = words.as_mut_slice();
let mut transposed = [0u64; WORDS_PER_CHUNK];
chunks.for_each_packed_chunk(|packed_chunk, range| {
let out = words[range.start / U64_BITS..]
.first_chunk_mut::<WORDS_PER_CHUNK>()
.vortex_expect("over-allocated buffer holds a full block per chunk");
unsafe {
<<T as PhysicalPType>::Physical as BitPackingCompare>::unchecked_unpack_cmp::<T, _>(
bit_width,
packed_chunk,
&mut transposed,
cmp,
rhs,
);
}
untranspose_bits::<<T as PhysicalPType>::Physical>(&transposed, out);
});
}
let mut bits = BitBufferMut::from_buffer(words.into_byte_buffer(), offset, len);
if let Some(p) = array.patches() {
let p_idx = p.indices().clone().execute::<PrimitiveArray>(ctx)?;
let p_val = p.values().clone().execute::<PrimitiveArray>(ctx)?;
let p_off = p.offset();
match_each_unsigned_integer_ptype!(p_idx.ptype(), |I| {
let indices = p_idx.as_slice::<I>();
let values = p_val.as_slice::<T>();
for (&global, &value) in indices.iter().zip(values) {
let global: usize = global.as_();
let idx = global - p_off;
bits.set_to(idx, cmp(value, rhs))
}
});
}
let validity = array.validity()?.union_nullability(nullability);
Ok(BoolArray::new(bits.freeze(), validity).into_array())
}