use std::iter;
use vortex_buffer::Alignment;
use vortex_buffer::Buffer;
use vortex_buffer::BufferMut;
use vortex_buffer::ByteBuffer;
use vortex_buffer::ByteBufferMut;
use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use vortex_error::vortex_err;
use crate::ToCanonical;
use crate::dtype::DType;
use crate::dtype::NativePType;
use crate::dtype::Nullability;
use crate::dtype::PType;
use crate::match_each_native_ptype;
use crate::stats::ArrayStats;
use crate::validity::Validity;
use crate::vtable::ValidityHelper;
mod accessor;
mod cast;
mod conversion;
mod patch;
mod top_value;
pub use patch::chunk_range;
pub use patch::patch_chunk;
use crate::buffer::BufferHandle;
#[derive(Clone, Debug)]
pub struct PrimitiveArray {
pub(super) dtype: DType,
pub(super) buffer: BufferHandle,
pub(super) validity: Validity,
pub(super) stats_set: ArrayStats,
}
pub struct PrimitiveArrayParts {
pub ptype: PType,
pub buffer: BufferHandle,
pub validity: Validity,
}
impl PrimitiveArray {
pub unsafe fn new_unchecked_from_handle(
handle: BufferHandle,
ptype: PType,
validity: Validity,
) -> Self {
Self {
buffer: handle,
dtype: DType::Primitive(ptype, validity.nullability()),
validity,
stats_set: ArrayStats::default(),
}
}
pub fn new<T: NativePType>(buffer: impl Into<Buffer<T>>, validity: Validity) -> Self {
let buffer = buffer.into();
Self::try_new(buffer, validity).vortex_expect("PrimitiveArray construction failed")
}
#[inline]
pub fn try_new<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> VortexResult<Self> {
Self::validate(&buffer, &validity)?;
Ok(unsafe { Self::new_unchecked(buffer, validity) })
}
#[inline]
pub unsafe fn new_unchecked<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> Self {
#[cfg(debug_assertions)]
Self::validate(&buffer, &validity)
.vortex_expect("[Debug Assertion]: Invalid `PrimitiveArray` parameters");
Self {
dtype: DType::Primitive(T::PTYPE, validity.nullability()),
buffer: BufferHandle::new_host(buffer.into_byte_buffer()),
validity,
stats_set: Default::default(),
}
}
#[inline]
pub fn validate<T: NativePType>(buffer: &Buffer<T>, validity: &Validity) -> VortexResult<()> {
if let Some(len) = validity.maybe_len()
&& buffer.len() != len
{
return Err(vortex_err!(
InvalidArgument:
"Buffer and validity length mismatch: buffer={}, validity={}",
buffer.len(),
len
));
}
Ok(())
}
pub fn empty<T: NativePType>(nullability: Nullability) -> Self {
Self::new(Buffer::<T>::empty(), nullability.into())
}
}
impl PrimitiveArray {
pub fn into_parts(self) -> PrimitiveArrayParts {
let ptype = self.ptype();
PrimitiveArrayParts {
ptype,
buffer: self.buffer,
validity: self.validity,
}
}
}
impl PrimitiveArray {
pub fn ptype(&self) -> PType {
self.dtype().as_ptype()
}
pub fn buffer_handle(&self) -> &BufferHandle {
&self.buffer
}
pub fn from_buffer_handle(handle: BufferHandle, ptype: PType, validity: Validity) -> Self {
let dtype = DType::Primitive(ptype, validity.nullability());
Self {
buffer: handle,
dtype,
validity,
stats_set: ArrayStats::default(),
}
}
pub fn from_byte_buffer(buffer: ByteBuffer, ptype: PType, validity: Validity) -> Self {
match_each_native_ptype!(ptype, |T| {
Self::new::<T>(Buffer::from_byte_buffer(buffer), validity)
})
}
pub fn from_values_byte_buffer(
valid_elems_buffer: ByteBuffer,
ptype: PType,
validity: Validity,
n_rows: usize,
) -> Self {
let byte_width = ptype.byte_width();
let alignment = Alignment::new(byte_width);
let buffer = match &validity {
Validity::AllValid | Validity::NonNullable => valid_elems_buffer.aligned(alignment),
Validity::AllInvalid => ByteBuffer::zeroed_aligned(n_rows * byte_width, alignment),
Validity::Array(is_valid) => {
let bool_array = is_valid.to_bool();
let bool_buffer = bool_array.to_bit_buffer();
let mut bytes = ByteBufferMut::zeroed_aligned(n_rows * byte_width, alignment);
for (i, valid_i) in bool_buffer.set_indices().enumerate() {
bytes[valid_i * byte_width..(valid_i + 1) * byte_width]
.copy_from_slice(&valid_elems_buffer[i * byte_width..(i + 1) * byte_width])
}
bytes.freeze()
}
};
Self::from_byte_buffer(buffer, ptype, validity)
}
pub fn map_each<T, R, F>(self, f: F) -> PrimitiveArray
where
T: NativePType,
R: NativePType,
F: FnMut(T) -> R,
{
let validity = self.validity().clone();
let buffer = match self.try_into_buffer_mut() {
Ok(buffer_mut) => buffer_mut.map_each_in_place(f),
Err(buffer) => BufferMut::from_iter(buffer.iter().copied().map(f)),
};
PrimitiveArray::new(buffer.freeze(), validity)
}
pub fn map_each_with_validity<T, R, F>(self, f: F) -> VortexResult<PrimitiveArray>
where
T: NativePType,
R: NativePType,
F: FnMut((T, bool)) -> R,
{
let validity = self.validity();
let buf_iter = self.to_buffer::<T>().into_iter();
let buffer = match &validity {
Validity::NonNullable | Validity::AllValid => {
BufferMut::<R>::from_iter(buf_iter.zip(iter::repeat(true)).map(f))
}
Validity::AllInvalid => {
BufferMut::<R>::from_iter(buf_iter.zip(iter::repeat(false)).map(f))
}
Validity::Array(val) => {
let val = val.to_bool().into_bit_buffer();
BufferMut::<R>::from_iter(buf_iter.zip(val.iter()).map(f))
}
};
Ok(PrimitiveArray::new(buffer.freeze(), validity.clone()))
}
}