vortex_array/arrays/bool/compute/
zip.rs1use vortex_buffer::BitBuffer;
5use vortex_buffer::BufferMut;
6use vortex_error::VortexResult;
7use vortex_mask::Mask;
8
9use crate::ArrayRef;
10use crate::ExecutionCtx;
11use crate::IntoArray;
12use crate::array::ArrayView;
13use crate::arrays::Bool;
14use crate::arrays::BoolArray;
15use crate::arrays::bool::BoolArrayExt;
16use crate::builtins::ArrayBuiltins;
17use crate::scalar_fn::fns::zip::ZipKernel;
18use crate::scalar_fn::fns::zip::zip_validity;
19
20impl ZipKernel for Bool {
27 fn zip(
28 if_true: ArrayView<'_, Bool>,
29 if_false: &ArrayRef,
30 mask: &ArrayRef,
31 ctx: &mut ExecutionCtx,
32 ) -> VortexResult<Option<ArrayRef>> {
33 let Some(if_false) = if_false.as_opt::<Bool>() else {
34 return Ok(None);
35 };
36
37 let mask = mask.clone().fill_null(false)?.execute::<Mask>(ctx)?;
39 let mask_values = match &mask {
40 Mask::AllTrue(_) | Mask::AllFalse(_) => return Ok(None),
42 Mask::Values(values) => values,
43 };
44 let mask_bits = mask_values.bit_buffer();
45
46 let values = zip_value_bits(
47 &if_true.to_bit_buffer(),
48 &if_false.to_bit_buffer(),
49 mask_bits,
50 );
51
52 let validity = zip_validity(if_true.validity()?, if_false.validity()?, &mask)?;
53
54 Ok(Some(BoolArray::new(values, validity).into_array()))
55 }
56}
57
58fn zip_value_bits(if_true: &BitBuffer, if_false: &BitBuffer, mask: &BitBuffer) -> BitBuffer {
59 assert_eq!(if_true.len(), if_false.len());
60 assert_eq!(if_true.len(), mask.len());
61
62 let true_chunks = if_true.chunks();
63 let false_chunks = if_false.chunks();
64 let mask_chunks = mask.chunks();
65
66 let mut values = BufferMut::<u64>::with_capacity(true_chunks.num_u64s());
67 for ((true_bits, false_bits), mask_bits) in true_chunks
68 .iter()
69 .zip(false_chunks.iter())
70 .zip(mask_chunks.iter())
71 {
72 values.push((true_bits & mask_bits) | (false_bits & !mask_bits));
73 }
74
75 if true_chunks.remainder_len() != 0 {
76 let true_bits = true_chunks.remainder_bits();
77 let false_bits = false_chunks.remainder_bits();
78 let mask_bits = mask_chunks.remainder_bits();
79 values.push((true_bits & mask_bits) | (false_bits & !mask_bits));
80 }
81
82 BitBuffer::new(values.freeze().into_byte_buffer(), if_true.len())
83}
84
85#[cfg(test)]
86mod tests {
87 use vortex_error::VortexResult;
88 use vortex_mask::Mask;
89
90 use super::zip_value_bits;
91 use crate::ArrayRef;
92 use crate::IntoArray;
93 use crate::VortexSessionExecute;
94 use crate::array_session;
95 use crate::arrays::Bool;
96 use crate::arrays::BoolArray;
97 use crate::assert_arrays_eq;
98 use crate::builtins::ArrayBuiltins;
99
100 #[test]
101 fn blend_value_bits_boundaries() {
102 for len in [0usize, 1, 2, 7, 8, 9, 63, 64, 65, 127, 128] {
103 let if_true = (0..len).map(|i| i.is_multiple_of(2)).collect();
104 let if_false = (0..len).map(|i| i.is_multiple_of(3)).collect();
105 let mask = (0..len).map(|i| i % 3 != 1).collect();
106
107 let values = zip_value_bits(&if_true, &if_false, &mask);
108
109 assert_eq!(values.len(), len);
110 assert_eq!(
111 values.iter().collect::<Vec<_>>(),
112 (0..len)
113 .map(|i| {
114 if i % 3 != 1 {
115 i.is_multiple_of(2)
116 } else {
117 i.is_multiple_of(3)
118 }
119 })
120 .collect::<Vec<_>>(),
121 "failed for len {len}",
122 );
123 }
124 }
125
126 #[test]
128 fn zip_nonnull_spans_mask_chunks() -> VortexResult<()> {
129 let len = 150usize;
130 let if_true = BoolArray::from_iter((0..len).map(|i| i.is_multiple_of(2))).into_array();
131 let if_false = BoolArray::from_iter((0..len).map(|i| i.is_multiple_of(3))).into_array();
132
133 let bits: Vec<bool> = (0..len).map(|i| i.is_multiple_of(5) || i == 64).collect();
134 let mask = Mask::from_iter(bits.iter().copied());
135
136 let mut ctx = array_session().create_execution_ctx();
137 let result = mask
138 .into_array()
139 .zip(if_true, if_false)?
140 .execute::<ArrayRef>(&mut ctx)?;
141 assert!(result.is::<Bool>());
142
143 let expected = BoolArray::from_iter((0..len).map(|i| {
144 if bits[i] {
145 i.is_multiple_of(2)
146 } else {
147 i.is_multiple_of(3)
148 }
149 }))
150 .into_array();
151 assert_arrays_eq!(result, expected, &mut ctx);
152 Ok(())
153 }
154
155 #[test]
157 fn zip_nullable_selects_values_and_validity() -> VortexResult<()> {
158 let len = 130usize;
159 let if_true = BoolArray::from_iter(
160 (0..len).map(|i| (!i.is_multiple_of(4)).then_some(i.is_multiple_of(2))),
161 )
162 .into_array();
163 let if_false = BoolArray::from_iter(
164 (0..len).map(|i| (!i.is_multiple_of(5)).then_some(i.is_multiple_of(3))),
165 )
166 .into_array();
167
168 let bits: Vec<bool> = (0..len).map(|i| i.is_multiple_of(2)).collect();
169 let mask = Mask::from_iter(bits.iter().copied());
170
171 let mut ctx = array_session().create_execution_ctx();
172 let result = mask
173 .into_array()
174 .zip(if_true, if_false)?
175 .execute::<ArrayRef>(&mut ctx)?;
176 assert!(result.is::<Bool>());
177
178 let expected = BoolArray::from_iter((0..len).map(|i| {
179 if bits[i] {
180 (!i.is_multiple_of(4)).then_some(i.is_multiple_of(2))
181 } else {
182 (!i.is_multiple_of(5)).then_some(i.is_multiple_of(3))
183 }
184 }))
185 .into_array();
186 assert_arrays_eq!(result, expected, &mut ctx);
187 Ok(())
188 }
189}