use polars_utils::IdxSize;
use super::FixedSizeListArray;
use crate::array::builder::{ArrayBuilder, ShareStrategy, StaticArrayBuilder};
use crate::bitmap::OptBitmapBuilder;
use crate::datatypes::ArrowDataType;
pub struct FixedSizeListArrayBuilder<B: ArrayBuilder> {
dtype: ArrowDataType,
size: usize,
length: usize,
inner_builder: B,
validity: OptBitmapBuilder,
}
impl<B: ArrayBuilder> FixedSizeListArrayBuilder<B> {
pub fn new(dtype: ArrowDataType, inner_builder: B) -> Self {
Self {
size: FixedSizeListArray::get_child_and_size(&dtype).1,
dtype,
length: 0,
inner_builder,
validity: OptBitmapBuilder::default(),
}
}
}
impl<B: ArrayBuilder> StaticArrayBuilder for FixedSizeListArrayBuilder<B> {
type Array = FixedSizeListArray;
fn dtype(&self) -> &ArrowDataType {
&self.dtype
}
fn reserve(&mut self, additional: usize) {
self.inner_builder.reserve(additional);
self.validity.reserve(additional);
}
fn freeze(self) -> FixedSizeListArray {
let values = self.inner_builder.freeze();
let validity = self.validity.into_opt_validity();
FixedSizeListArray::new(self.dtype, self.length, values, validity)
}
fn freeze_reset(&mut self) -> Self::Array {
let values = self.inner_builder.freeze_reset();
let validity = core::mem::take(&mut self.validity).into_opt_validity();
let out = FixedSizeListArray::new(self.dtype.clone(), self.length, values, validity);
self.length = 0;
out
}
fn len(&self) -> usize {
self.length
}
fn extend_nulls(&mut self, length: usize) {
self.inner_builder.extend_nulls(length * self.size);
self.validity.extend_constant(length, false);
self.length += length;
}
fn subslice_extend(
&mut self,
other: &FixedSizeListArray,
start: usize,
length: usize,
share: ShareStrategy,
) {
self.inner_builder.subslice_extend(
&**other.values(),
start * self.size,
length * self.size,
share,
);
self.validity
.subslice_extend_from_opt_validity(other.validity(), start, length);
self.length += length.min(other.len().saturating_sub(start));
}
fn subslice_extend_each_repeated(
&mut self,
other: &FixedSizeListArray,
start: usize,
length: usize,
repeats: usize,
share: ShareStrategy,
) {
let other_values = &**other.values();
self.inner_builder.reserve(repeats * length * self.size);
for outer_idx in start..start + length {
self.inner_builder.subslice_extend_repeated(
other_values,
outer_idx * self.size,
self.size,
repeats,
share,
);
}
self.validity
.subslice_extend_each_repeated_from_opt_validity(
other.validity(),
start,
length,
repeats,
);
self.length += repeats * length.min(other.len().saturating_sub(start));
}
unsafe fn gather_extend(
&mut self,
other: &FixedSizeListArray,
idxs: &[IdxSize],
share: ShareStrategy,
) {
let other_values = &**other.values();
self.inner_builder.reserve(idxs.len() * self.size);
let mut group_start = 0;
while group_start < idxs.len() {
let start_idx = idxs[group_start] as usize;
let mut group_len = 1;
while group_start + group_len < idxs.len()
&& idxs[group_start + group_len] as usize == start_idx + group_len
{
group_len += 1;
}
self.inner_builder.subslice_extend(
other_values,
start_idx * self.size,
group_len * self.size,
share,
);
group_start += group_len;
}
self.validity
.gather_extend_from_opt_validity(other.validity(), idxs);
self.length += idxs.len();
}
fn opt_gather_extend(
&mut self,
other: &FixedSizeListArray,
idxs: &[IdxSize],
share: ShareStrategy,
) {
let other_values = &**other.values();
self.inner_builder.reserve(idxs.len() * self.size);
let mut group_start = 0;
while group_start < idxs.len() {
let start_idx = idxs[group_start] as usize;
let mut group_len = 1;
let in_bounds = start_idx < other.len();
if in_bounds {
while group_start + group_len < idxs.len()
&& idxs[group_start + group_len] as usize == start_idx + group_len
&& start_idx + group_len < other.len()
{
group_len += 1;
}
self.inner_builder.subslice_extend(
other_values,
start_idx * self.size,
group_len * self.size,
share,
);
} else {
while group_start + group_len < idxs.len()
&& idxs[group_start + group_len] as usize >= other.len()
{
group_len += 1;
}
self.inner_builder.extend_nulls(group_len * self.size);
}
group_start += group_len;
}
self.validity
.opt_gather_extend_from_opt_validity(other.validity(), idxs, other.len());
self.length += idxs.len();
}
}