use std::ops::Range;
use either::Either;
use polars_buffer::Buffer;
use polars_utils::float16::pf16;
use super::{Array, Splitable};
use crate::array::iterator::NonNullValuesIter;
use crate::bitmap::Bitmap;
use crate::bitmap::utils::{BitmapIter, ZipValidity};
use crate::datatypes::*;
use crate::trusted_len::TrustedLen;
use crate::types::{NativeType, days_ms, i256, months_days_ns};
mod ffi;
pub(super) mod fmt;
mod from_natural;
pub mod iterator;
#[cfg(feature = "proptest")]
pub mod proptest;
mod mutable;
pub use mutable::*;
mod builder;
pub use builder::*;
use polars_error::{PolarsResult, polars_bail};
use polars_utils::index::{Bounded, Indexable, NullCount};
use polars_utils::slice::SliceAble;
#[derive(Clone)]
pub struct PrimitiveArray<T: NativeType> {
dtype: ArrowDataType,
values: Buffer<T>,
validity: Option<Bitmap>,
}
pub(super) fn check<T: NativeType>(
dtype: &ArrowDataType,
values: &[T],
validity_len: Option<usize>,
) -> PolarsResult<()> {
if validity_len.is_some_and(|len| len != values.len()) {
polars_bail!(ComputeError: "validity mask length must match the number of values")
}
if dtype.to_physical_type() != PhysicalType::Primitive(T::PRIMITIVE) {
polars_bail!(ComputeError: "PrimitiveArray can only be initialized with a DataType whose physical type is Primitive")
}
Ok(())
}
impl<T: NativeType> PrimitiveArray<T> {
pub fn try_new(
dtype: ArrowDataType,
values: Buffer<T>,
validity: Option<Bitmap>,
) -> PolarsResult<Self> {
check(&dtype, &values, validity.as_ref().map(|v| v.len()))?;
Ok(Self {
dtype,
values,
validity,
})
}
pub unsafe fn new_unchecked(
dtype: ArrowDataType,
values: Buffer<T>,
validity: Option<Bitmap>,
) -> Self {
if cfg!(debug_assertions) {
check(&dtype, &values, validity.as_ref().map(|v| v.len())).unwrap();
}
Self {
dtype,
values,
validity,
}
}
#[inline]
#[must_use]
pub fn to(self, dtype: ArrowDataType) -> Self {
check(
&dtype,
&self.values,
self.validity.as_ref().map(|v| v.len()),
)
.unwrap();
Self {
dtype,
values: self.values,
validity: self.validity,
}
}
pub fn from_vec(values: Vec<T>) -> Self {
Self::new(T::PRIMITIVE.into(), values.into(), None)
}
#[inline]
pub fn iter(&self) -> ZipValidity<&T, std::slice::Iter<'_, T>, BitmapIter<'_>> {
ZipValidity::new_with_validity(self.values().iter(), self.validity())
}
#[inline]
pub fn values_iter(&self) -> std::slice::Iter<'_, T> {
self.values().iter()
}
#[inline]
pub fn non_null_values_iter(&self) -> NonNullValuesIter<'_, [T]> {
NonNullValuesIter::new(self.values(), self.validity())
}
#[inline]
pub fn len(&self) -> usize {
self.values.len()
}
#[inline]
pub fn values(&self) -> &Buffer<T> {
&self.values
}
#[inline]
pub fn validity(&self) -> Option<&Bitmap> {
self.validity.as_ref()
}
#[inline]
pub fn dtype(&self) -> &ArrowDataType {
&self.dtype
}
#[inline]
pub fn value(&self, i: usize) -> T {
self.values[i]
}
#[inline]
pub unsafe fn value_unchecked(&self, i: usize) -> T {
*self.values.get_unchecked(i)
}
#[inline]
pub fn slice(&mut self, offset: usize, length: usize) {
assert!(
offset + length <= self.len(),
"offset + length may not exceed length of array"
);
unsafe { self.slice_unchecked(offset, length) }
}
#[inline]
pub unsafe fn slice_unchecked(&mut self, offset: usize, length: usize) {
self.validity = self
.validity
.take()
.map(|bitmap| bitmap.sliced_unchecked(offset, length))
.filter(|bitmap| bitmap.unset_bits() > 0);
self.values
.slice_in_place_unchecked(offset..offset + length);
}
impl_sliced!();
impl_mut_validity!();
impl_into_array!();
#[must_use]
pub fn with_values(mut self, values: Buffer<T>) -> Self {
self.set_values(values);
self
}
pub fn set_values(&mut self, values: Buffer<T>) {
assert_eq!(
values.len(),
self.len(),
"values' length must be equal to this arrays' length"
);
self.values = values;
}
pub fn apply_validity<F: FnOnce(Bitmap) -> Bitmap>(&mut self, f: F) {
if let Some(validity) = std::mem::take(&mut self.validity) {
self.set_validity(Some(f(validity)))
}
}
pub fn with_values_mut<F: FnOnce(&mut [T])>(&mut self, f: F) {
if let Some(slice) = self.values.get_mut_slice() {
f(slice)
} else {
let mut values = self.values.as_slice().to_vec();
f(&mut values);
self.values = Buffer::from(values);
}
}
pub fn get_mut_values(&mut self) -> Option<&mut [T]> {
self.values.get_mut_slice()
}
#[must_use]
pub fn into_inner(self) -> (ArrowDataType, Buffer<T>, Option<Bitmap>) {
let Self {
dtype,
values,
validity,
} = self;
(dtype, values, validity)
}
pub fn from_inner(
dtype: ArrowDataType,
values: Buffer<T>,
validity: Option<Bitmap>,
) -> PolarsResult<Self> {
check(&dtype, &values, validity.as_ref().map(|v| v.len()))?;
Ok(unsafe { Self::from_inner_unchecked(dtype, values, validity) })
}
pub unsafe fn from_inner_unchecked(
dtype: ArrowDataType,
values: Buffer<T>,
validity: Option<Bitmap>,
) -> Self {
Self {
dtype,
values,
validity,
}
}
#[must_use]
pub fn into_mut(self) -> Either<Self, MutablePrimitiveArray<T>> {
use Either::*;
if let Some(bitmap) = self.validity {
match bitmap.into_mut() {
Left(bitmap) => Left(PrimitiveArray::new(self.dtype, self.values, Some(bitmap))),
Right(mutable_bitmap) => match self.values.into_mut() {
Right(values) => Right(
MutablePrimitiveArray::try_new(self.dtype, values, Some(mutable_bitmap))
.unwrap(),
),
Left(values) => Left(PrimitiveArray::new(
self.dtype,
values,
Some(mutable_bitmap.into()),
)),
},
}
} else {
match self.values.into_mut() {
Right(values) => {
Right(MutablePrimitiveArray::try_new(self.dtype, values, None).unwrap())
},
Left(values) => Left(PrimitiveArray::new(self.dtype, values, None)),
}
}
}
pub fn new_empty(dtype: ArrowDataType) -> Self {
Self::new(dtype, Buffer::new(), None)
}
#[inline]
pub fn new_null(dtype: ArrowDataType, length: usize) -> Self {
Self::new(
dtype,
vec![T::default(); length].into(),
Some(Bitmap::new_zeroed(length)),
)
}
pub fn from_values<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self::new(T::PRIMITIVE.into(), Vec::<T>::from_iter(iter).into(), None)
}
pub fn from_slice<P: AsRef<[T]>>(slice: P) -> Self {
Self::new(
T::PRIMITIVE.into(),
Vec::<T>::from(slice.as_ref()).into(),
None,
)
}
pub fn from_trusted_len_values_iter<I: TrustedLen<Item = T>>(iter: I) -> Self {
MutablePrimitiveArray::<T>::from_trusted_len_values_iter(iter).into()
}
pub unsafe fn from_trusted_len_values_iter_unchecked<I: Iterator<Item = T>>(iter: I) -> Self {
MutablePrimitiveArray::<T>::from_trusted_len_values_iter_unchecked(iter).into()
}
pub fn from_trusted_len_iter<I: TrustedLen<Item = Option<T>>>(iter: I) -> Self {
MutablePrimitiveArray::<T>::from_trusted_len_iter(iter).into()
}
pub unsafe fn from_trusted_len_iter_unchecked<I: Iterator<Item = Option<T>>>(iter: I) -> Self {
MutablePrimitiveArray::<T>::from_trusted_len_iter_unchecked(iter).into()
}
pub fn new(dtype: ArrowDataType, values: Buffer<T>, validity: Option<Bitmap>) -> Self {
Self::try_new(dtype, values, validity).unwrap()
}
pub fn transmute<U: NativeType>(self) -> PrimitiveArray<U> {
let PrimitiveArray {
values, validity, ..
} = self;
PrimitiveArray::new(
U::PRIMITIVE.into(),
Buffer::try_transmute::<U>(values).unwrap(),
validity,
)
}
pub fn fill_with(mut self, value: T) -> Self {
if let Some(values) = self.get_mut_values() {
for x in values.iter_mut() {
*x = value;
}
self
} else {
let values = vec![value; self.len()];
Self::new(T::PRIMITIVE.into(), values.into(), self.validity)
}
}
}
impl<T: NativeType> Array for PrimitiveArray<T> {
impl_common_array!();
fn validity(&self) -> Option<&Bitmap> {
self.validity.as_ref()
}
#[inline]
fn with_validity(&self, validity: Option<Bitmap>) -> Box<dyn Array> {
Box::new(self.clone().with_validity(validity))
}
}
impl<T: NativeType> Splitable for PrimitiveArray<T> {
#[inline(always)]
fn check_bound(&self, offset: usize) -> bool {
offset <= self.len()
}
unsafe fn _split_at_unchecked(&self, offset: usize) -> (Self, Self) {
let (lhs_values, rhs_values) = unsafe { self.values.split_at_unchecked(offset) };
let (lhs_validity, rhs_validity) = unsafe { self.validity.split_at_unchecked(offset) };
(
Self {
dtype: self.dtype.clone(),
values: lhs_values,
validity: lhs_validity,
},
Self {
dtype: self.dtype.clone(),
values: rhs_values,
validity: rhs_validity,
},
)
}
}
impl<T: NativeType> SliceAble for PrimitiveArray<T> {
unsafe fn slice_unchecked(&self, range: Range<usize>) -> Self {
self.clone().sliced_unchecked(range.start, range.len())
}
fn slice(&self, range: Range<usize>) -> Self {
self.clone().sliced(range.start, range.len())
}
}
impl<T: NativeType> Indexable for PrimitiveArray<T> {
type Item = Option<T>;
fn get(&self, i: usize) -> Self::Item {
if !self.is_null(i) {
unsafe { Some(self.value_unchecked(i)) }
} else {
None
}
}
unsafe fn get_unchecked(&self, i: usize) -> Self::Item {
if !self.is_null_unchecked(i) {
Some(self.value_unchecked(i))
} else {
None
}
}
}
pub type Int8Array = PrimitiveArray<i8>;
pub type Int16Array = PrimitiveArray<i16>;
pub type Int32Array = PrimitiveArray<i32>;
pub type Int64Array = PrimitiveArray<i64>;
pub type Int128Array = PrimitiveArray<i128>;
pub type Int256Array = PrimitiveArray<i256>;
pub type DaysMsArray = PrimitiveArray<days_ms>;
pub type MonthsDaysNsArray = PrimitiveArray<months_days_ns>;
pub type Float16Array = PrimitiveArray<pf16>;
pub type Float32Array = PrimitiveArray<f32>;
pub type Float64Array = PrimitiveArray<f64>;
pub type UInt8Array = PrimitiveArray<u8>;
pub type UInt16Array = PrimitiveArray<u16>;
pub type UInt32Array = PrimitiveArray<u32>;
pub type UInt64Array = PrimitiveArray<u64>;
pub type UInt128Array = PrimitiveArray<u128>;
pub type Int8Vec = MutablePrimitiveArray<i8>;
pub type Int16Vec = MutablePrimitiveArray<i16>;
pub type Int32Vec = MutablePrimitiveArray<i32>;
pub type Int64Vec = MutablePrimitiveArray<i64>;
pub type Int128Vec = MutablePrimitiveArray<i128>;
pub type Int256Vec = MutablePrimitiveArray<i256>;
pub type DaysMsVec = MutablePrimitiveArray<days_ms>;
pub type MonthsDaysNsVec = MutablePrimitiveArray<months_days_ns>;
pub type Float16Vec = MutablePrimitiveArray<pf16>;
pub type Float32Vec = MutablePrimitiveArray<f32>;
pub type Float64Vec = MutablePrimitiveArray<f64>;
pub type UInt8Vec = MutablePrimitiveArray<u8>;
pub type UInt16Vec = MutablePrimitiveArray<u16>;
pub type UInt32Vec = MutablePrimitiveArray<u32>;
pub type UInt64Vec = MutablePrimitiveArray<u64>;
pub type UInt128Vec = MutablePrimitiveArray<u128>;
impl<T: NativeType> Default for PrimitiveArray<T> {
fn default() -> Self {
PrimitiveArray::new(T::PRIMITIVE.into(), Default::default(), None)
}
}
impl<T: NativeType> Bounded for PrimitiveArray<T> {
fn len(&self) -> usize {
self.values.len()
}
}
impl<T: NativeType> NullCount for PrimitiveArray<T> {
fn null_count(&self) -> usize {
<Self as Array>::null_count(self)
}
}