vortex_array/arrays/bool/compute/
take.rs1use itertools::Itertools as _;
5use num_traits::AsPrimitive;
6use vortex_buffer::BitBuffer;
7use vortex_buffer::BitBufferView;
8use vortex_buffer::get_bit;
9use vortex_error::VortexResult;
10use vortex_mask::Mask;
11
12use crate::ArrayRef;
13use crate::IntoArray;
14use crate::array::ArrayView;
15use crate::arrays::Bool;
16use crate::arrays::BoolArray;
17use crate::arrays::ConstantArray;
18use crate::arrays::PrimitiveArray;
19use crate::arrays::bool::BoolArrayExt;
20use crate::arrays::dict::TakeExecute;
21use crate::builtins::ArrayBuiltins;
22use crate::executor::ExecutionCtx;
23use crate::match_each_integer_ptype;
24use crate::scalar::Scalar;
25
26impl TakeExecute for Bool {
27 fn take(
28 array: ArrayView<'_, Bool>,
29 indices: &ArrayRef,
30 ctx: &mut ExecutionCtx,
31 ) -> VortexResult<Option<ArrayRef>> {
32 let indices_nulls_zeroed = match indices.validity()?.execute_mask(indices.len(), ctx)? {
33 Mask::AllTrue(_) => indices.clone(),
34 Mask::AllFalse(_) => {
35 return Ok(Some(
36 ConstantArray::new(Scalar::null(array.dtype().as_nullable()), indices.len())
37 .into_array(),
38 ));
39 }
40 Mask::Values(_) => indices
41 .clone()
42 .fill_null(Scalar::from(0).cast(indices.dtype())?)?,
43 };
44 let indices_nulls_zeroed = indices_nulls_zeroed.execute::<PrimitiveArray>(ctx)?;
45 let buffer = match_each_integer_ptype!(indices_nulls_zeroed.ptype(), |I| {
46 take_valid_indices(
47 array.bit_buffer_view(),
48 indices_nulls_zeroed.as_slice::<I>(),
49 )
50 });
51
52 Ok(Some(
53 BoolArray::new(buffer, array.validity()?.take(indices)?).into_array(),
54 ))
55 }
56}
57
58fn take_valid_indices<I: AsPrimitive<usize>>(bools: BitBufferView<'_>, indices: &[I]) -> BitBuffer {
59 if bools.len() <= 4096 {
62 let bools = bools.iter().collect_vec();
63 take_byte_bool(bools, indices)
64 } else {
65 take_bool_impl(bools, indices)
66 }
67}
68
69fn take_byte_bool<I: AsPrimitive<usize>>(bools: Vec<bool>, indices: &[I]) -> BitBuffer {
70 BitBuffer::collect_bool(indices.len(), |idx| {
71 bools[unsafe { indices.get_unchecked(idx).as_() }]
72 })
73}
74
75fn take_bool_impl<I: AsPrimitive<usize>>(bools: BitBufferView<'_>, indices: &[I]) -> BitBuffer {
76 let buffer = bools.inner();
78 BitBuffer::collect_bool(indices.len(), |idx| {
79 let idx = unsafe { indices.get_unchecked(idx).as_() };
81 get_bit(buffer, bools.offset() + idx)
82 })
83}
84
85#[cfg(test)]
86mod test {
87 use rstest::rstest;
88 use vortex_buffer::buffer;
89
90 use crate::IntoArray as _;
91 use crate::VortexSessionExecute;
92 use crate::array_session;
93 use crate::arrays::BoolArray;
94 use crate::arrays::PrimitiveArray;
95 use crate::arrays::bool::BoolArrayExt;
96 use crate::assert_arrays_eq;
97 use crate::compute::conformance::take::test_take_conformance;
98 use crate::validity::Validity;
99
100 #[test]
101 fn take_nullable() {
102 let mut ctx = array_session().create_execution_ctx();
103 let reference = BoolArray::from_iter(vec![
104 Some(false),
105 Some(true),
106 Some(false),
107 None,
108 Some(false),
109 ]);
110
111 let b = reference
112 .take(buffer![0, 3, 4].into_array())
113 .unwrap()
114 .execute::<BoolArray>(&mut ctx)
115 .unwrap();
116 assert_eq!(
117 b.to_bit_buffer(),
118 BoolArray::from_iter([Some(false), None, Some(false)]).to_bit_buffer()
119 );
120
121 let all_invalid_indices = PrimitiveArray::from_option_iter([None::<i32>, None, None]);
122 let b = reference.take(all_invalid_indices.into_array()).unwrap();
123 assert_arrays_eq!(b, BoolArray::from_iter([None, None, None]), &mut ctx);
124 }
125
126 #[test]
127 fn test_bool_array_take_with_null_out_of_bounds_indices() {
128 let mut ctx = array_session().create_execution_ctx();
129 let values = BoolArray::from_iter(vec![Some(false), Some(true), None, None, Some(false)]);
130 let indices = PrimitiveArray::new(
131 buffer![0, 3, 100],
132 Validity::Array(BoolArray::from_iter([true, true, false]).into_array()),
133 );
134 let actual = values.take(indices.into_array()).unwrap();
135
136 assert_arrays_eq!(
138 actual,
139 BoolArray::from_iter([Some(false), None, None]),
140 &mut ctx
141 );
142 }
143
144 #[test]
145 fn test_non_null_bool_array_take_with_null_out_of_bounds_indices() {
146 let mut ctx = array_session().create_execution_ctx();
147 let values = BoolArray::from_iter(vec![false, true, false, true, false]);
148 let indices = PrimitiveArray::new(
149 buffer![0, 3, 100],
150 Validity::Array(BoolArray::from_iter([true, true, false]).into_array()),
151 );
152 let actual = values.take(indices.into_array()).unwrap();
153 assert_arrays_eq!(
155 actual,
156 BoolArray::from_iter([Some(false), Some(true), None]),
157 &mut ctx
158 );
159 }
160
161 #[test]
162 fn test_bool_array_take_all_null_indices() {
163 let mut ctx = array_session().create_execution_ctx();
164 let values = BoolArray::from_iter(vec![Some(false), Some(true), None, None, Some(false)]);
165 let indices = PrimitiveArray::new(
166 buffer![0, 3, 100],
167 Validity::Array(BoolArray::from_iter([false, false, false]).into_array()),
168 );
169 let actual = values.take(indices.into_array()).unwrap();
170 assert_arrays_eq!(actual, BoolArray::from_iter([None, None, None]), &mut ctx);
171 }
172
173 #[test]
174 fn test_non_null_bool_array_take_all_null_indices() {
175 let mut ctx = array_session().create_execution_ctx();
176 let values = BoolArray::from_iter(vec![false, true, false, true, false]);
177 let indices = PrimitiveArray::new(
178 buffer![0, 3, 100],
179 Validity::Array(BoolArray::from_iter([false, false, false]).into_array()),
180 );
181 let actual = values.take(indices.into_array()).unwrap();
182 assert_arrays_eq!(actual, BoolArray::from_iter([None, None, None]), &mut ctx);
183 }
184
185 #[rstest]
186 #[case(BoolArray::from_iter([true, false, true, true, false]))]
187 #[case(BoolArray::from_iter([Some(true), None, Some(false), Some(true), None]))]
188 #[case(BoolArray::from_iter([true, false]))]
189 #[case(BoolArray::from_iter([true]))]
190 fn test_take_bool_conformance(#[case] array: BoolArray) {
191 test_take_conformance(
192 &array.into_array(),
193 &mut array_session().create_execution_ctx(),
194 );
195 }
196}