polars_core/chunked_array/ops/
reverse.rs

1#[cfg(feature = "dtype-array")]
2use crate::chunked_array::builder::get_fixed_size_list_builder;
3use crate::prelude::*;
4use crate::series::IsSorted;
5use crate::utils::NoNull;
6
7impl<T> ChunkReverse for ChunkedArray<T>
8where
9    T: PolarsNumericType,
10{
11    fn reverse(&self) -> ChunkedArray<T> {
12        let mut out = if let Ok(slice) = self.cont_slice() {
13            let ca: NoNull<ChunkedArray<T>> = slice.iter().rev().copied().collect_trusted();
14            ca.into_inner()
15        } else {
16            self.into_iter().rev().collect_trusted()
17        };
18        out.rename(self.name().clone());
19
20        match self.is_sorted_flag() {
21            IsSorted::Ascending => out.set_sorted_flag(IsSorted::Descending),
22            IsSorted::Descending => out.set_sorted_flag(IsSorted::Ascending),
23            _ => {},
24        }
25
26        out
27    }
28}
29
30macro_rules! impl_reverse {
31    ($arrow_type:ident, $ca_type:ident) => {
32        impl ChunkReverse for $ca_type {
33            fn reverse(&self) -> Self {
34                if self.is_empty() {
35                    return self.clone();
36                };
37                let mut ca: Self = self.into_iter().rev().collect_trusted();
38                ca.rename(self.name().clone());
39                ca
40            }
41        }
42    };
43}
44
45impl_reverse!(BooleanType, BooleanChunked);
46impl_reverse!(BinaryOffsetType, BinaryOffsetChunked);
47impl_reverse!(ListType, ListChunked);
48
49impl ChunkReverse for BinaryChunked {
50    fn reverse(&self) -> Self {
51        if self.chunks.len() == 1 {
52            let arr = self.downcast_iter().next().unwrap();
53            let views = arr.views().iter().copied().rev().collect::<Vec<_>>();
54
55            unsafe {
56                let arr = BinaryViewArray::new_unchecked(
57                    arr.dtype().clone(),
58                    views.into(),
59                    arr.data_buffers().clone(),
60                    arr.validity().map(|bitmap| bitmap.iter().rev().collect()),
61                    arr.total_bytes_len(),
62                    arr.total_buffer_len(),
63                )
64                .boxed();
65                BinaryChunked::from_chunks_and_dtype_unchecked(
66                    self.name().clone(),
67                    vec![arr],
68                    self.dtype().clone(),
69                )
70            }
71        } else {
72            let ca = IdxCa::from_vec(
73                PlSmallStr::EMPTY,
74                (0..self.len() as IdxSize).rev().collect(),
75            );
76            unsafe { self.take_unchecked(&ca) }
77        }
78    }
79}
80
81impl ChunkReverse for StringChunked {
82    fn reverse(&self) -> Self {
83        unsafe { self.as_binary().reverse().to_string_unchecked() }
84    }
85}
86
87#[cfg(feature = "dtype-array")]
88impl ChunkReverse for ArrayChunked {
89    fn reverse(&self) -> Self {
90        if !self.inner_dtype().is_primitive_numeric() {
91            todo!("reverse for FixedSizeList with non-numeric dtypes not yet supported")
92        }
93        let ca = self.rechunk();
94        let arr = ca.downcast_as_array();
95        let values = arr.values().as_ref();
96
97        let mut builder =
98            get_fixed_size_list_builder(ca.inner_dtype(), ca.len(), ca.width(), ca.name().clone())
99                .expect("not yet supported");
100
101        // SAFETY, we are within bounds
102        unsafe {
103            if arr.null_count() == 0 {
104                for i in (0..arr.len()).rev() {
105                    builder.push_unchecked(values, i)
106                }
107            } else {
108                let validity = arr.validity().unwrap();
109                for i in (0..arr.len()).rev() {
110                    if validity.get_bit_unchecked(i) {
111                        builder.push_unchecked(values, i)
112                    } else {
113                        builder.push_null()
114                    }
115                }
116            }
117        }
118        builder.finish()
119    }
120}
121
122#[cfg(feature = "object")]
123impl<T: PolarsObject> ChunkReverse for ObjectChunked<T> {
124    fn reverse(&self) -> Self {
125        // SAFETY: we know we don't go out of bounds.
126        unsafe {
127            self.take_unchecked(
128                &(0..self.len() as IdxSize)
129                    .rev()
130                    .collect_ca(PlSmallStr::EMPTY),
131            )
132        }
133    }
134}