use arrow::compute::concatenate::concatenate;
use arrow::Either;
use crate::prelude::append::update_sorted_flag_before_append;
use crate::prelude::*;
use crate::series::IsSorted;
fn extend_immutable(immutable: &dyn Array, chunks: &mut Vec<ArrayRef>, other_chunks: &[ArrayRef]) {
let out = if chunks.len() == 1 {
concatenate(&[immutable, &*other_chunks[0]]).unwrap()
} else {
let mut arrays = Vec::with_capacity(other_chunks.len() + 1);
arrays.push(immutable);
arrays.extend(other_chunks.iter().map(|a| &**a));
concatenate(&arrays).unwrap()
};
chunks.push(out);
}
impl<T> ChunkedArray<T>
where
T: PolarsNumericType,
{
pub fn extend(&mut self, other: &Self) {
update_sorted_flag_before_append::<T>(self, other);
if self.chunks.len() > 1 {
self.append(other);
*self = self.rechunk();
return;
}
let arr = self.downcast_iter().next().unwrap();
let arr = arr.clone();
{
self.chunks.clear();
}
use Either::*;
if arr.values().is_sliced() {
extend_immutable(&arr, &mut self.chunks, &other.chunks);
} else {
match arr.into_mut() {
Left(immutable) => {
extend_immutable(&immutable, &mut self.chunks, &other.chunks);
},
Right(mut mutable) => {
for arr in other.downcast_iter() {
match arr.null_count() {
0 => mutable.extend_from_slice(arr.values()),
_ => mutable.extend_trusted_len(arr.into_iter()),
}
}
let arr: PrimitiveArray<T::Native> = mutable.into();
self.chunks.push(Box::new(arr) as ArrayRef)
},
}
}
self.compute_len();
}
}
#[doc(hidden)]
impl StringChunked {
pub fn extend(&mut self, other: &Self) {
self.set_sorted_flag(IsSorted::Not);
self.append(other)
}
}
#[doc(hidden)]
impl BinaryChunked {
pub fn extend(&mut self, other: &Self) {
self.set_sorted_flag(IsSorted::Not);
self.append(other)
}
}
#[doc(hidden)]
impl BinaryOffsetChunked {
pub fn extend(&mut self, other: &Self) {
self.set_sorted_flag(IsSorted::Not);
self.append(other)
}
}
#[doc(hidden)]
impl BooleanChunked {
pub fn extend(&mut self, other: &Self) {
update_sorted_flag_before_append::<BooleanType>(self, other);
if self.chunks.len() > 1 {
self.append(other);
*self = self.rechunk();
return;
}
let arr = self.downcast_iter().next().unwrap();
let arr = arr.clone();
{
self.chunks.clear();
}
use Either::*;
match arr.into_mut() {
Left(immutable) => {
extend_immutable(&immutable, &mut self.chunks, &other.chunks);
},
Right(mut mutable) => {
for arr in other.downcast_iter() {
mutable.extend_trusted_len(arr.into_iter())
}
let arr: BooleanArray = mutable.into();
self.chunks.push(Box::new(arr) as ArrayRef)
},
}
self.compute_len();
self.set_sorted_flag(IsSorted::Not);
}
}
#[doc(hidden)]
impl ListChunked {
pub fn extend(&mut self, other: &Self) -> PolarsResult<()> {
self.set_sorted_flag(IsSorted::Not);
self.append(other)
}
}
#[cfg(feature = "dtype-array")]
#[doc(hidden)]
impl ArrayChunked {
pub fn extend(&mut self, other: &Self) -> PolarsResult<()> {
self.set_sorted_flag(IsSorted::Not);
self.append(other)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[allow(clippy::redundant_clone)]
fn test_extend_primitive() {
let mut values = Vec::with_capacity(32);
values.extend_from_slice(&[1, 2, 3]);
let mut ca = Int32Chunked::from_vec("a", values);
let location = ca.cont_slice().unwrap().as_ptr() as usize;
let to_append = Int32Chunked::new("a", &[4, 5, 6]);
ca.extend(&to_append);
let location2 = ca.cont_slice().unwrap().as_ptr() as usize;
assert_eq!(location, location2);
assert_eq!(ca.cont_slice().unwrap(), [1, 2, 3, 4, 5, 6]);
let _temp = ca.chunks.clone();
ca.extend(&to_append);
let location2 = ca.cont_slice().unwrap().as_ptr() as usize;
assert_ne!(location, location2);
assert_eq!(ca.cont_slice().unwrap(), [1, 2, 3, 4, 5, 6, 4, 5, 6]);
}
#[test]
fn test_extend_string() {
let mut ca = StringChunked::new("a", &["a", "b", "c"]);
let to_append = StringChunked::new("a", &["a", "b", "e"]);
ca.extend(&to_append);
assert_eq!(ca.len(), 6);
let vals = ca.into_no_null_iter().collect::<Vec<_>>();
assert_eq!(vals, ["a", "b", "c", "a", "b", "e"])
}
#[test]
fn test_extend_bool() {
let mut ca = BooleanChunked::new("a", [true, false]);
let to_append = BooleanChunked::new("a", &[false, false]);
ca.extend(&to_append);
assert_eq!(ca.len(), 4);
let vals = ca.into_no_null_iter().collect::<Vec<_>>();
assert_eq!(vals, [true, false, false, false]);
}
}