Skip to main content

vortex_array/arrays/masked/compute/
take.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use vortex_error::VortexResult;
5
6use crate::ArrayRef;
7use crate::IntoArray;
8use crate::array::ArrayView;
9use crate::arrays::Masked;
10use crate::arrays::MaskedArray;
11use crate::arrays::dict::TakeReduce;
12use crate::arrays::masked::MaskedArraySlotsExt;
13use crate::builtins::ArrayBuiltins;
14use crate::scalar::Scalar;
15use crate::validity::Validity;
16
17impl TakeReduce for Masked {
18    fn take(array: ArrayView<'_, Masked>, indices: &ArrayRef) -> VortexResult<Option<ArrayRef>> {
19        let indices_all_valid = matches!(
20            indices.validity()?,
21            Validity::NonNullable | Validity::AllValid
22        );
23        let taken_child = if !indices_all_valid {
24            // This is safe because we'll mask out these positions in the validity.
25            let fill_scalar = Scalar::zero_value(indices.dtype());
26            let filled_take_indices = indices.clone().fill_null(fill_scalar)?;
27            array.child().take(filled_take_indices)?
28        } else {
29            array.child().take(indices.clone())?
30        };
31
32        // Compute the new validity by taking from array's validity and merging with indices validity
33        let taken_validity = array.validity()?.take(indices)?;
34
35        // SAFETY: the child is null-free and is taken with non-null indices, so the taken child is
36        // null-free. The child and validity are taken by the same indices, so their lengths match.
37        Ok(Some(
38            unsafe { MaskedArray::new_unchecked(taken_child, taken_validity) }.into_array(),
39        ))
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use rstest::rstest;
46
47    use crate::IntoArray;
48    use crate::VortexSessionExecute;
49    use crate::array_session;
50    use crate::arrays::MaskedArray;
51    use crate::arrays::PrimitiveArray;
52    use crate::compute::conformance::take::test_take_conformance;
53    use crate::validity::Validity;
54
55    #[rstest]
56    #[case(
57        MaskedArray::try_new(
58            PrimitiveArray::from_iter([1i32, 2, 3, 4, 5]).into_array(),
59            Validity::from_iter([true, true, false, true, false]),
60            &mut array_session().create_execution_ctx(),
61        ).unwrap()
62    )]
63    #[case(
64        MaskedArray::try_new(
65            PrimitiveArray::from_iter([10i32, 20, 30]).into_array(),
66            Validity::AllValid,
67            &mut array_session().create_execution_ctx(),
68        ).unwrap()
69    )]
70    #[case(
71        MaskedArray::try_new(
72            PrimitiveArray::from_iter(0..100).into_array(),
73            Validity::from_iter((0..100).map(|i| i % 3 != 0)),
74            &mut array_session().create_execution_ctx(),
75        ).unwrap()
76    )]
77    fn test_take_masked_conformance(#[case] array: MaskedArray) {
78        test_take_conformance(
79            &array.into_array(),
80            &mut array_session().create_execution_ctx(),
81        );
82    }
83}