1use itertools::Itertools;
10use vortex_array::ArrayRef;
11use vortex_array::IntoArray;
12use vortex_array::arrays::BoolArray;
13use vortex_array::arrays::ConstantArray;
14use vortex_array::arrays::PrimitiveArray;
15use vortex_array::arrays::bool::BoolArrayExt;
16use vortex_array::dtype::DType;
17use vortex_array::dtype::Nullability;
18use vortex_array::match_each_unsigned_integer_ptype;
19use vortex_array::scalar::Scalar;
20use vortex_array::validity::Validity;
21use vortex_buffer::BitBuffer;
22use vortex_buffer::BitBufferMut;
23use vortex_error::VortexResult;
24use vortex_mask::Mask;
25
26use crate::iter::trimmed_ends_iter;
27
28const PREFILL_RUN_THRESHOLD: usize = 32;
31
32pub fn runend_decode_bools(
34 ends: PrimitiveArray,
35 values: BoolArray,
36 offset: usize,
37 length: usize,
38) -> VortexResult<ArrayRef> {
39 let validity = values.validity_mask()?;
40 let values_buf = values.to_bit_buffer();
41 let nullability = values.dtype().nullability();
42
43 let num_runs = values_buf.len();
45 if offset == 0 && num_runs < PREFILL_RUN_THRESHOLD {
46 return Ok(match_each_unsigned_integer_ptype!(ends.ptype(), |E| {
47 decode_few_runs_no_offset(
48 ends.as_slice::<E>(),
49 &values_buf,
50 validity,
51 nullability,
52 length,
53 )
54 }));
55 }
56
57 Ok(match_each_unsigned_integer_ptype!(ends.ptype(), |E| {
58 runend_decode_typed_bool(
59 trimmed_ends_iter(ends.as_slice::<E>(), offset, length),
60 &values_buf,
61 validity,
62 nullability,
63 length,
64 )
65 }))
66}
67
68pub fn runend_decode_typed_bool(
76 run_ends: impl Iterator<Item = usize>,
77 values: &BitBuffer,
78 values_validity: Mask,
79 values_nullability: Nullability,
80 length: usize,
81) -> ArrayRef {
82 match values_validity {
83 Mask::AllTrue(_) => {
84 decode_bool_non_nullable(run_ends, values, values_nullability, length).into_array()
85 }
86 Mask::AllFalse(_) => {
87 ConstantArray::new(Scalar::null(DType::Bool(Nullability::Nullable)), length)
88 .into_array()
89 }
90 Mask::Values(mask) => {
91 decode_bool_nullable(run_ends, values, mask.bit_buffer(), length).into_array()
92 }
93 }
94}
95
96#[inline(always)]
100fn decode_few_runs_no_offset<E: vortex_array::dtype::IntegerPType>(
101 ends: &[E],
102 values: &BitBuffer,
103 validity: Mask,
104 nullability: Nullability,
105 length: usize,
106) -> ArrayRef {
107 match validity {
108 Mask::AllTrue(_) => {
109 let mut decoded = BitBufferMut::with_capacity(length);
110 let mut prev_end = 0usize;
111 for (i, &end) in ends.iter().enumerate() {
112 let end = end.as_().min(length);
113 decoded.append_n(values.value(i), end - prev_end);
114 prev_end = end;
115 }
116 BoolArray::new(decoded.freeze(), nullability.into()).into_array()
117 }
118 Mask::AllFalse(_) => {
119 ConstantArray::new(Scalar::null(DType::Bool(Nullability::Nullable)), length)
120 .into_array()
121 }
122 Mask::Values(mask) => {
123 let validity_buf = mask.bit_buffer();
124 let mut decoded = BitBufferMut::with_capacity(length);
125 let mut decoded_validity = BitBufferMut::with_capacity(length);
126 let mut prev_end = 0usize;
127 for (i, &end) in ends.iter().enumerate() {
128 let end = end.as_().min(length);
129 let run_len = end - prev_end;
130 let is_valid = validity_buf.value(i);
131 if is_valid {
132 decoded_validity.append_n(true, run_len);
133 decoded.append_n(values.value(i), run_len);
134 } else {
135 decoded_validity.append_n(false, run_len);
136 decoded.append_n(false, run_len);
137 }
138 prev_end = end;
139 }
140 BoolArray::new(decoded.freeze(), Validity::from(decoded_validity.freeze())).into_array()
141 }
142 }
143}
144
145fn decode_bool_non_nullable(
147 run_ends: impl Iterator<Item = usize>,
148 values: &BitBuffer,
149 nullability: Nullability,
150 length: usize,
151) -> BoolArray {
152 let num_runs = values.len();
153
154 if num_runs < PREFILL_RUN_THRESHOLD {
156 let mut decoded = BitBufferMut::with_capacity(length);
157 for (end, value) in run_ends.zip(values.iter()) {
158 decoded.append_n(value, end - decoded.len());
159 }
160 return BoolArray::new(decoded.freeze(), nullability.into());
161 }
162
163 let prefill = values.true_count() > num_runs - values.true_count();
165 let mut decoded = BitBufferMut::full(prefill, length);
166 let mut current_pos = 0usize;
167
168 for (end, value) in run_ends.zip_eq(values.iter()) {
169 if end > current_pos && value != prefill {
170 unsafe { decoded.fill_range_unchecked(current_pos, end, value) };
172 }
173 current_pos = end;
174 }
175 BoolArray::new(decoded.freeze(), nullability.into())
176}
177
178fn decode_bool_nullable(
180 run_ends: impl Iterator<Item = usize>,
181 values: &BitBuffer,
182 validity_mask: &BitBuffer,
183 length: usize,
184) -> BoolArray {
185 let num_runs = values.len();
186
187 if num_runs < PREFILL_RUN_THRESHOLD {
189 return decode_nullable_sequential(run_ends, values, validity_mask, length);
190 }
191
192 let prefill_decoded = values.true_count() > num_runs - values.true_count();
194 let prefill_valid = validity_mask.true_count() > num_runs - validity_mask.true_count();
195
196 let mut decoded = BitBufferMut::full(prefill_decoded, length);
197 let mut decoded_validity = BitBufferMut::full(prefill_valid, length);
198 let mut current_pos = 0usize;
199
200 for (end, (value, is_valid)) in run_ends.zip_eq(values.iter().zip(validity_mask.iter())) {
201 if end > current_pos {
202 if is_valid != prefill_valid {
204 unsafe { decoded_validity.fill_range_unchecked(current_pos, end, is_valid) };
205 }
206 let want_decoded = is_valid && value;
208 if want_decoded != prefill_decoded {
209 unsafe { decoded.fill_range_unchecked(current_pos, end, want_decoded) };
210 }
211 current_pos = end;
212 }
213 }
214 BoolArray::new(decoded.freeze(), Validity::from(decoded_validity.freeze()))
215}
216
217#[inline(always)]
219fn decode_nullable_sequential(
220 run_ends: impl Iterator<Item = usize>,
221 values: &BitBuffer,
222 validity_mask: &BitBuffer,
223 length: usize,
224) -> BoolArray {
225 let mut decoded = BitBufferMut::with_capacity(length);
226 let mut decoded_validity = BitBufferMut::with_capacity(length);
227
228 for (end, (value, is_valid)) in run_ends.zip(values.iter().zip(validity_mask.iter())) {
229 let run_len = end - decoded.len();
230 if is_valid {
231 decoded_validity.append_n(true, run_len);
232 decoded.append_n(value, run_len);
233 } else {
234 decoded_validity.append_n(false, run_len);
235 decoded.append_n(false, run_len);
236 }
237 }
238
239 BoolArray::new(decoded.freeze(), Validity::from(decoded_validity.freeze()))
240}
241
242#[cfg(test)]
243mod tests {
244 use vortex_array::ToCanonical;
245 use vortex_array::arrays::BoolArray;
246 use vortex_array::arrays::PrimitiveArray;
247 use vortex_array::arrays::bool::BoolArrayExt;
248 use vortex_array::assert_arrays_eq;
249 use vortex_array::validity::Validity;
250 use vortex_buffer::BitBuffer;
251 use vortex_error::VortexResult;
252
253 use super::runend_decode_bools;
254
255 #[test]
256 fn decode_bools_alternating() -> VortexResult<()> {
257 let ends = PrimitiveArray::from_iter([2u32, 5, 10]);
259 let values = BoolArray::from(BitBuffer::from(vec![true, false, true]));
260 let decoded = runend_decode_bools(ends, values, 0, 10)?;
261
262 let expected = BoolArray::from(BitBuffer::from(vec![
263 true, true, false, false, false, true, true, true, true, true,
264 ]));
265 assert_arrays_eq!(decoded, expected);
266 Ok(())
267 }
268
269 #[test]
270 fn decode_bools_mostly_true() -> VortexResult<()> {
271 let ends = PrimitiveArray::from_iter([5u32, 6, 10]);
273 let values = BoolArray::from(BitBuffer::from(vec![true, false, true]));
274 let decoded = runend_decode_bools(ends, values, 0, 10)?;
275
276 let expected = BoolArray::from(BitBuffer::from(vec![
277 true, true, true, true, true, false, true, true, true, true,
278 ]));
279 assert_arrays_eq!(decoded, expected);
280 Ok(())
281 }
282
283 #[test]
284 fn decode_bools_mostly_false() -> VortexResult<()> {
285 let ends = PrimitiveArray::from_iter([5u32, 6, 10]);
287 let values = BoolArray::from(BitBuffer::from(vec![false, true, false]));
288 let decoded = runend_decode_bools(ends, values, 0, 10)?;
289
290 let expected = BoolArray::from(BitBuffer::from(vec![
291 false, false, false, false, false, true, false, false, false, false,
292 ]));
293 assert_arrays_eq!(decoded, expected);
294 Ok(())
295 }
296
297 #[test]
298 fn decode_bools_all_true_single_run() -> VortexResult<()> {
299 let ends = PrimitiveArray::from_iter([10u32]);
300 let values = BoolArray::from(BitBuffer::from(vec![true]));
301 let decoded = runend_decode_bools(ends, values, 0, 10)?;
302
303 let expected = BoolArray::from(BitBuffer::from(vec![
304 true, true, true, true, true, true, true, true, true, true,
305 ]));
306 assert_arrays_eq!(decoded, expected);
307 Ok(())
308 }
309
310 #[test]
311 fn decode_bools_all_false_single_run() -> VortexResult<()> {
312 let ends = PrimitiveArray::from_iter([10u32]);
313 let values = BoolArray::from(BitBuffer::from(vec![false]));
314 let decoded = runend_decode_bools(ends, values, 0, 10)?;
315
316 let expected = BoolArray::from(BitBuffer::from(vec![
317 false, false, false, false, false, false, false, false, false, false,
318 ]));
319 assert_arrays_eq!(decoded, expected);
320 Ok(())
321 }
322
323 #[test]
324 fn decode_bools_with_offset() -> VortexResult<()> {
325 let ends = PrimitiveArray::from_iter([2u32, 5, 10]);
327 let values = BoolArray::from(BitBuffer::from(vec![true, false, true]));
328 let decoded = runend_decode_bools(ends, values, 2, 6)?;
329
330 let expected =
331 BoolArray::from(BitBuffer::from(vec![false, false, false, true, true, true]));
332 assert_arrays_eq!(decoded, expected);
333 Ok(())
334 }
335
336 #[test]
337 fn decode_bools_nullable() -> VortexResult<()> {
338 use vortex_array::validity::Validity;
339
340 let ends = PrimitiveArray::from_iter([2u32, 5, 10]);
342 let values = BoolArray::new(
343 BitBuffer::from(vec![true, false, true]),
344 Validity::from(BitBuffer::from(vec![true, false, true])),
345 );
346 let decoded = runend_decode_bools(ends, values, 0, 10)?;
347
348 let expected = BoolArray::new(
350 BitBuffer::from(vec![
351 true, true, false, false, false, true, true, true, true, true,
352 ]),
353 Validity::from(BitBuffer::from(vec![
354 true, true, false, false, false, true, true, true, true, true,
355 ])),
356 );
357 assert_arrays_eq!(decoded, expected);
358 Ok(())
359 }
360
361 #[test]
362 fn decode_bools_nullable_few_runs() -> VortexResult<()> {
363 let ends = PrimitiveArray::from_iter([2000u32, 4000, 6000, 8000, 10000]);
365 let values = BoolArray::new(
366 BitBuffer::from(vec![true, false, true, false, true]),
367 Validity::from(BitBuffer::from(vec![true, false, true, false, true])),
368 );
369 let decoded = runend_decode_bools(ends, values, 0, 10000)?.to_bool();
370
371 assert_eq!(decoded.len(), 10000);
373 assert!(decoded.validity_mask()?.value(0));
375 assert!(decoded.to_bit_buffer().value(0));
376 assert!(!decoded.validity_mask()?.value(2000));
378 assert!(decoded.validity_mask()?.value(4000));
380 assert!(decoded.to_bit_buffer().value(4000));
381 Ok(())
382 }
383}