1use super::RowSelector;
27use arrow_buffer::bit_iterator::BitSliceIterator;
28use arrow_buffer::{BooleanBuffer, BooleanBufferBuilder, Buffer};
29use std::sync::OnceLock;
30
31#[derive(Debug)]
44pub(crate) struct MaskSelection {
45 mask: BooleanBuffer,
46 selectors: OnceLock<Vec<RowSelector>>,
47 count: OnceLock<usize>,
48}
49
50impl MaskSelection {
51 pub(super) fn new(mask: BooleanBuffer) -> Self {
52 Self {
53 mask,
54 selectors: OnceLock::new(),
55 count: OnceLock::new(),
56 }
57 }
58
59 pub(super) fn with_count(mask: BooleanBuffer, count: usize) -> Self {
61 debug_assert!(count <= mask.len());
62 let cell = OnceLock::new();
63 let _ = cell.set(count);
64 Self {
65 mask,
66 selectors: OnceLock::new(),
67 count: cell,
68 }
69 }
70
71 pub(crate) fn mask(&self) -> &BooleanBuffer {
72 &self.mask
73 }
74
75 pub(crate) fn into_mask(self) -> BooleanBuffer {
76 let Self { mask, .. } = self;
77 mask
78 }
79
80 pub(super) fn count(&self) -> usize {
82 *self.count.get_or_init(|| self.mask.count_set_bits())
83 }
84
85 pub(super) fn cached_count(&self) -> Option<usize> {
87 self.count.get().copied()
88 }
89
90 pub(super) fn selectors(&self) -> &[RowSelector] {
91 self.selectors
92 .get_or_init(|| mask_to_selectors(&self.mask))
93 .as_slice()
94 }
95}
96
97impl Clone for MaskSelection {
98 fn clone(&self) -> Self {
99 Self {
101 mask: self.mask.clone(),
102 selectors: OnceLock::new(),
103 count: self.count.clone(),
104 }
105 }
106}
107
108#[derive(Debug)]
123pub struct MaskRunIter<'a> {
124 slices: BitSliceIterator<'a>,
125 cursor: usize,
126 total: usize,
127 pending: Option<RowSelector>,
128 finished: bool,
129}
130
131impl<'a> MaskRunIter<'a> {
132 pub fn new(mask: &'a BooleanBuffer) -> Self {
134 Self {
135 slices: mask.set_slices(),
136 cursor: 0,
137 total: mask.len(),
138 pending: None,
139 finished: false,
140 }
141 }
142}
143
144impl Iterator for MaskRunIter<'_> {
145 type Item = RowSelector;
146
147 fn next(&mut self) -> Option<RowSelector> {
148 if let Some(p) = self.pending.take() {
149 return Some(p);
150 }
151 if self.finished {
152 return None;
153 }
154 match self.slices.next() {
155 Some((start, end)) => {
156 let select = RowSelector::select(end - start);
157 if start > self.cursor {
158 let skip = RowSelector::skip(start - self.cursor);
159 self.pending = Some(select);
160 self.cursor = end;
161 Some(skip)
162 } else {
163 self.cursor = end;
164 Some(select)
165 }
166 }
167 None => {
168 self.finished = true;
169 if self.cursor < self.total {
170 let skip = RowSelector::skip(self.total - self.cursor);
171 self.cursor = self.total;
172 Some(skip)
173 } else {
174 None
175 }
176 }
177 }
178 }
179}
180
181pub(crate) fn mask_to_selectors(mask: &BooleanBuffer) -> Vec<RowSelector> {
183 let total_rows = mask.len();
184 if total_rows == 0 {
185 return Vec::new();
186 }
187 let mut selectors: Vec<RowSelector> = Vec::new();
188 let mut last_end = 0;
189 for (start, end) in mask.set_slices() {
190 if start > last_end {
191 selectors.push(RowSelector::skip(start - last_end));
192 }
193 selectors.push(RowSelector::select(end - start));
194 last_end = end;
195 }
196 if last_end != total_rows {
197 selectors.push(RowSelector::skip(total_rows - last_end));
198 }
199 selectors
200}
201
202pub(super) fn mask_has_at_least_runs(mask: &BooleanBuffer, min_runs: usize) -> bool {
207 if min_runs == 0 {
208 return true;
209 }
210
211 let total_rows = mask.len();
212 if total_rows == 0 {
213 return false;
214 }
215
216 let mut run_count = 0;
217 let mut last_end = 0;
218 for (start, end) in mask.set_slices() {
219 run_count += usize::from(start > last_end) + 1;
220 if run_count >= min_runs {
221 return true;
222 }
223 last_end = end;
224 }
225
226 run_count + usize::from(last_end < total_rows) >= min_runs
227}
228
229pub(super) fn split_off_mask(
232 mask: BooleanBuffer,
233 row_count: usize,
234) -> (BooleanBuffer, BooleanBuffer) {
235 let total = mask.len();
236 if row_count >= total {
237 return (mask, BooleanBuffer::new_unset(0));
238 }
239
240 let head = mask.slice(0, row_count);
241 let tail = mask.slice(row_count, total - row_count);
242 (head, tail)
243}
244
245fn last_set_bit_position(mask: &BooleanBuffer) -> Option<usize> {
247 let values = mask.values();
248 let offset = mask.offset();
249 let end = offset + mask.len();
250 for byte_idx in (offset / 8..end.div_ceil(8)).rev() {
251 let byte_start = byte_idx * 8;
252 let mut byte = values[byte_idx];
253 if end - byte_start < 8 {
254 byte &= (1u8 << (end - byte_start)) - 1;
255 }
256 if byte_start < offset {
257 byte &= !((1u8 << (offset - byte_start)) - 1);
258 }
259 if byte != 0 {
260 return Some(byte_start + 7 - byte.leading_zeros() as usize - offset);
261 }
262 }
263 None
264}
265
266pub(super) fn trim_mask(mask: &BooleanBuffer) -> Option<BooleanBuffer> {
268 let len = mask.len();
269 if len == 0 || mask.value(len - 1) {
271 return None;
272 }
273 let new_len = last_set_bit_position(mask).map_or(0, |pos| pos + 1);
274 Some(mask.slice(0, new_len))
275}
276
277pub(super) fn offset_mask(mask: BooleanBuffer, offset: usize, popcount: usize) -> BooleanBuffer {
280 if offset >= popcount {
281 return BooleanBuffer::new_unset(0);
282 }
283 let pos = mask.find_nth_set_bit_position(0, offset);
286 let mut builder = BooleanBufferBuilder::new(mask.len());
287 builder.append_n(pos, false);
288 builder.append_buffer(&mask.slice(pos, mask.len() - pos));
289 builder.finish()
290}
291
292pub(super) fn limit_mask(mask: BooleanBuffer, limit: usize) -> BooleanBuffer {
294 let cut = mask.find_nth_set_bit_position(0, limit);
298 mask.slice(0, cut)
299}
300
301fn set_bit_run(buf: &mut [u8], start: usize, len: usize) {
303 if len == 0 {
304 return;
305 }
306 let end = start + len;
307 let first_byte = start / 8;
308 let last_byte = (end - 1) / 8;
309 let start_mask = 0xFFu8 << (start % 8);
310 let end_mask = 0xFFu8 >> (8 - (end - last_byte * 8));
311 if first_byte == last_byte {
312 buf[first_byte] |= start_mask & end_mask;
313 } else {
314 buf[first_byte] |= start_mask;
315 buf[first_byte + 1..last_byte].fill(0xFF);
316 buf[last_byte] |= end_mask;
317 }
318}
319
320pub(super) fn boolean_mask_from_selectors(selectors: &[RowSelector]) -> BooleanBuffer {
325 let total_rows: usize = selectors.iter().map(|s| s.row_count).sum();
326 let mut buf = vec![0u8; total_rows.div_ceil(8)];
327 let mut position = 0usize;
328 for selector in selectors {
329 if !selector.skip {
330 set_bit_run(&mut buf, position, selector.row_count);
331 }
332 position += selector.row_count;
333 }
334 BooleanBuffer::new(Buffer::from(buf), 0, total_rows)
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340 use crate::arrow::arrow_reader::selection::{RowSelection, RowSelectionInner};
341 use arrow_array::BooleanArray;
342 use rand::{Rng, rng};
343
344 #[test]
345 fn test_mask_iter_yields_borrowed_selectors() {
346 let selection = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
347 false, false, true, true, false, true, false, false,
348 ]));
349
350 let borrowed: Vec<&RowSelector> = selection.iter().collect();
351 assert_eq!(
352 borrowed,
353 vec![
354 &RowSelector::skip(2),
355 &RowSelector::select(2),
356 &RowSelector::skip(1),
357 &RowSelector::select(1),
358 &RowSelector::skip(2),
359 ]
360 );
361 }
362
363 #[test]
364 fn test_mask_iter_clone_drops_cache() {
365 let selection = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
366 false, false, true, true, false, true, false, false,
367 ]));
368
369 let _ = selection.iter().count();
370 match &selection.inner {
371 RowSelectionInner::Mask(m) => assert!(m.selectors.get().is_some()),
372 _ => unreachable!(),
373 }
374
375 let cloned = selection.clone();
376 match &cloned.inner {
377 RowSelectionInner::Mask(m) => assert!(m.selectors.get().is_none()),
378 _ => unreachable!(),
379 }
380
381 let round_tripped: Vec<RowSelector> = cloned.iter().copied().collect();
382 assert_eq!(
383 round_tripped,
384 vec![
385 RowSelector::skip(2),
386 RowSelector::select(2),
387 RowSelector::skip(1),
388 RowSelector::select(1),
389 RowSelector::skip(2),
390 ]
391 );
392 }
393
394 #[test]
395 fn test_mask_run_iter_streams_without_cache() {
396 let selection = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
397 false, false, true, true, false, true, false, false,
398 ]));
399 let mut iter = MaskRunIter::new(selection.as_mask().unwrap());
400
401 assert_eq!(iter.next(), Some(RowSelector::skip(2)));
402 assert_eq!(iter.next(), Some(RowSelector::select(2)));
403 assert_eq!(iter.next(), Some(RowSelector::skip(1)));
404 assert_eq!(iter.next(), Some(RowSelector::select(1)));
405 assert_eq!(iter.next(), Some(RowSelector::skip(2)));
406 assert_eq!(iter.next(), None);
407 assert_eq!(iter.next(), None);
408
409 let selection =
410 RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![true, true, false]));
411 let mut iter = MaskRunIter::new(selection.as_mask().unwrap());
412 assert_eq!(iter.next(), Some(RowSelector::select(2)));
413 assert_eq!(iter.next(), Some(RowSelector::skip(1)));
414 assert_eq!(iter.next(), None);
415 }
416
417 #[test]
418 fn test_from_boolean_buffer() {
419 let bits = vec![
420 false, false, true, true, false, true, false, false, true, false, false, false, false,
421 false, false, true,
422 ];
423 let buf = BooleanBuffer::from(bits.clone());
424 let selection = RowSelection::from_boolean_buffer(buf.clone());
425
426 assert!(selection.as_mask().is_some());
427 assert_eq!(selection.row_count(), 5);
428 assert_eq!(selection.skipped_row_count(), 11);
429 assert!(selection.selects_any());
430
431 let from_filters = RowSelection::from_filters(&[BooleanArray::from(bits)]);
432 assert_eq!(selection, from_filters);
433
434 let bits_tail = vec![true, false, true, false, false, false];
435 let trimmed = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits_tail)).trim();
436 assert!(trimmed.as_mask().is_some());
437 assert_eq!(trimmed.as_mask().unwrap().len(), 3);
438 }
439
440 #[test]
441 fn test_from_boolean_buffer_empty() {
442 let empty = RowSelection::from_boolean_buffer(BooleanBuffer::from(Vec::<bool>::new()));
443 assert!(empty.as_mask().is_some());
444 assert_eq!(empty.row_count(), 0);
445 assert_eq!(empty.skipped_row_count(), 0);
446 assert!(!empty.selects_any());
447 assert!(empty.selectors().is_empty());
448 }
449
450 #[test]
451 fn test_from_boolean_buffer_all_unset_does_not_select() {
452 let all_zero = RowSelection::from_boolean_buffer(BooleanBuffer::new_unset(1024));
453 assert!(all_zero.as_mask().is_some());
454 assert!(!all_zero.selects_any());
455 assert_eq!(all_zero.row_count(), 0);
456 assert_eq!(all_zero.skipped_row_count(), 1024);
457 }
458
459 #[test]
460 fn test_from_boolean_buffer_via_from_impl() {
461 let buf = BooleanBuffer::from(vec![true, false, true, true]);
462 let a = RowSelection::from(buf.clone());
463 let b = RowSelection::from_boolean_buffer(buf);
464 assert_eq!(a, b);
465 assert!(a.as_mask().is_some());
466 }
467
468 #[test]
469 fn test_mask_backing_clone_preserves_backing() {
470 let buf = BooleanBuffer::from(vec![true, false, true]);
471 let original = RowSelection::from_boolean_buffer(buf);
472 let cloned = original.clone();
473 assert!(cloned.as_mask().is_some());
474 assert_eq!(original, cloned);
475 }
476
477 #[test]
478 fn test_mask_backing_mutation_equivalence() {
479 let bits = vec![true, true, false, false, true, false, true, true];
480
481 let from_mask = {
482 let mut s = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone()));
483 let split = s.split_off(3);
484 (split, s)
485 };
486 let from_selectors = {
487 let mut s = RowSelection::from_filters(&[BooleanArray::from(bits.clone())]);
488 let split = s.split_off(3);
489 (split, s)
490 };
491 assert_eq!(from_mask.0, from_selectors.0);
492 assert_eq!(from_mask.1, from_selectors.1);
493 assert!(from_mask.0.as_mask().is_some());
494 assert!(from_mask.1.as_mask().is_some());
495
496 let limited_mask =
497 RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone())).limit(3);
498 let limited_sel = RowSelection::from_filters(&[BooleanArray::from(bits.clone())]).limit(3);
499 assert!(limited_mask.as_mask().is_some());
500 assert_eq!(limited_mask, limited_sel);
501
502 let offset_mask =
503 RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone())).offset(2);
504 let offset_sel = RowSelection::from_filters(&[BooleanArray::from(bits)]).offset(2);
505 assert!(offset_mask.as_mask().is_some());
506 assert_eq!(offset_mask, offset_sel);
507 }
508
509 #[test]
510 fn test_mask_backing_fuzz_equivalence() {
511 let mut rand = rng();
512 for _ in 0..100 {
513 let len = rand.random_range(0..200);
514 let bits: Vec<_> = (0..len).map(|_| rand.random_bool(0.35)).collect();
515
516 let from_mask = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone()));
517 let from_filters = RowSelection::from_filters(&[BooleanArray::from(bits.clone())]);
518
519 assert_eq!(from_mask, from_filters);
520 assert_eq!(from_mask.row_count(), from_filters.row_count());
521 assert_eq!(
522 from_mask.skipped_row_count(),
523 from_filters.skipped_row_count()
524 );
525 assert_eq!(from_mask.selects_any(), from_filters.selects_any());
526
527 let inner_len: usize = bits.iter().map(|b| *b as usize).sum();
528 let inner_bits: Vec<_> = (0..inner_len).map(|_| rand.random_bool(0.7)).collect();
529 let inner = RowSelection::from_filters(&[BooleanArray::from(inner_bits.clone())]);
530 let inner_mask = RowSelection::from_boolean_buffer(BooleanBuffer::from(inner_bits));
531 let and_then_mask = from_mask.and_then(&inner);
532 let and_then_both_masks = from_mask.and_then(&inner_mask);
533 assert!(and_then_mask.as_mask().is_some());
534 assert!(and_then_both_masks.as_mask().is_some());
535 assert_eq!(and_then_mask, from_filters.and_then(&inner));
536 assert_eq!(and_then_both_masks, and_then_mask);
537 }
538 }
539
540 #[test]
541 fn test_mask_offset_past_end_preserves_empty_mask_backing() {
542 let selection =
543 RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![true, false, true]))
544 .offset(2);
545
546 assert!(selection.as_mask().is_some());
547 assert_eq!(selection.as_mask().unwrap().len(), 0);
548 assert_eq!(selection.row_count(), 0);
549 assert_eq!(selection.skipped_row_count(), 0);
550 }
551
552 #[test]
553 fn test_mask_limit_truncates_at_nth_selected_row() {
554 let selection = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
555 false, true, false, true, false, true, false,
556 ]))
557 .limit(2);
558
559 let mask = selection.as_mask().unwrap();
560 assert_eq!(mask.len(), 4);
561 let actual_bits: Vec<_> = (0..mask.len()).map(|i| mask.value(i)).collect();
562 assert_eq!(actual_bits, vec![false, true, false, true]);
563 }
564
565 #[test]
566 fn test_mask_split_off_preserves_backing() {
567 let bits: Vec<bool> = (0..40).map(|i| i % 3 == 0).collect();
568 let mut s = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone()));
569 let head = s.split_off(15);
570
571 assert!(head.as_mask().is_some());
572 assert!(s.as_mask().is_some());
573
574 let head_sel = RowSelection::from_filters(&[BooleanArray::from(bits[..15].to_vec())]);
575 let tail_sel = RowSelection::from_filters(&[BooleanArray::from(bits[15..].to_vec())]);
576 assert_eq!(head, head_sel);
577 assert_eq!(s, tail_sel);
578 }
579
580 #[test]
581 fn test_mask_split_off_past_end_returns_whole() {
582 let bits = vec![true, false, true];
583 let mut s = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone()));
584 let head = s.split_off(100);
585
586 assert!(head.as_mask().is_some());
587 assert_eq!(head.as_mask().unwrap().len(), 3);
588 assert!(s.as_mask().is_some());
590 assert_eq!(s.as_mask().unwrap().len(), 0);
591 assert_eq!(s.row_count(), 0);
592 assert_eq!(s.skipped_row_count(), 0);
593 }
594
595 #[test]
596 fn test_mask_offset_exceeds_selected_returns_empty() {
597 let s =
598 RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![true, true, false, true]));
599 let r = s.offset(10);
600 assert_eq!(r.row_count(), 0);
601 assert_eq!(r.skipped_row_count(), 0);
602
603 let from_selectors =
604 RowSelection::from_filters(&[BooleanArray::from(vec![true, true, false, true])])
605 .offset(10);
606 assert_eq!(r, from_selectors);
607 }
608
609 #[test]
610 fn test_mask_limit_exceeds_selected_returns_all() {
611 let bits = vec![true, true, false, true];
612 let s = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone()));
613 let r = s.limit(10);
614 assert_eq!(r.row_count(), 3);
615
616 let from_selectors = RowSelection::from_filters(&[BooleanArray::from(bits)]).limit(10);
617 assert_eq!(r, from_selectors);
618 }
619
620 #[test]
621 fn test_mask_trim_all_zero_collapses_to_empty() {
622 let s = RowSelection::from_boolean_buffer(BooleanBuffer::new_unset(128));
623 let trimmed = s.trim();
624 assert!(trimmed.as_mask().is_some());
625 assert_eq!(trimmed.as_mask().unwrap().len(), 0);
626 }
627
628 #[test]
629 fn test_boolean_mask_from_selectors_fuzz_equivalence() {
630 let mut rand = rng();
631 for _ in 0..200 {
632 let n_selectors = rand.random_range(0..30);
633 let mut selectors = Vec::with_capacity(n_selectors);
634 for _ in 0..n_selectors {
635 selectors.push(RowSelector {
636 row_count: rand.random_range(0..40),
637 skip: rand.random_bool(0.5),
638 });
639 }
640
641 let expected = {
642 let total_rows: usize = selectors.iter().map(|s| s.row_count).sum();
643 let mut builder = BooleanBufferBuilder::new(total_rows);
644 for selector in &selectors {
645 builder.append_n(selector.row_count, !selector.skip);
646 }
647 builder.finish()
648 };
649
650 assert_eq!(boolean_mask_from_selectors(&selectors), expected);
651 }
652 }
653
654 #[test]
655 fn test_mask_has_at_least_runs() {
656 fn assert_run_count(bits: Vec<bool>, expected_runs: usize) {
657 let mask = BooleanBuffer::from(bits);
658 for min_runs in 0..=expected_runs + 2 {
659 assert_eq!(
660 mask_has_at_least_runs(&mask, min_runs),
661 expected_runs >= min_runs,
662 "expected {expected_runs} runs with boundary {min_runs}"
663 );
664 }
665 }
666
667 assert_run_count(vec![], 0);
668 assert_run_count(vec![false; 8], 1);
669 assert_run_count(vec![true; 8], 1);
670 assert_run_count(vec![false, false, true, true, false], 3);
671 assert_run_count(vec![true, false, true, false, true, false], 6);
672
673 let mask = BooleanBuffer::from(vec![true, false, false, true, true, false, true, true])
675 .slice(1, 6);
676 for min_runs in 0..=6 {
677 assert_eq!(mask_has_at_least_runs(&mask, min_runs), 4 >= min_runs);
678 }
679 }
680
681 #[test]
682 fn test_trim_mask_fuzz_equivalence() {
683 let mut rand = rng();
684 for _ in 0..200 {
685 let len = rand.random_range(0..200);
686 let bits: Vec<bool> = (0..len).map(|_| rand.random_bool(0.3)).collect();
687 let full = BooleanBuffer::from(bits.clone());
688 let start = rand.random_range(0..=len);
690 let slice_len = rand.random_range(0..=(len - start));
691 let mask = full.slice(start, slice_len);
692
693 let expected_len = bits[start..start + slice_len]
694 .iter()
695 .rposition(|&b| b)
696 .map_or(0, |pos| pos + 1);
697
698 match trim_mask(&mask) {
699 Some(trimmed) => {
700 assert_ne!(expected_len, mask.len());
701 assert_eq!(trimmed.len(), expected_len);
702 assert_eq!(trimmed, mask.slice(0, expected_len));
703 }
704 None => assert_eq!(expected_len, mask.len()),
705 }
706 }
707 }
708
709 #[test]
710 fn test_split_off_propagates_cached_count() {
711 let bits = vec![true, false, true, true, false, false, true, false];
712 let mut selection = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits));
713 assert_eq!(selection.row_count(), 4);
715 let head = selection.split_off(3);
716 assert_eq!(head.row_count(), 2);
717 assert_eq!(selection.row_count(), 2);
718 let tail_fresh = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
719 true, false, false, true, false,
720 ]));
721 assert_eq!(selection, tail_fresh);
722
723 let head = selection.split_off(100);
725 assert_eq!(head.row_count(), 2);
726 assert_eq!(selection.row_count(), 0);
727 }
728
729 #[test]
730 fn test_trim_and_offset_and_limit_preserve_cached_count() {
731 let bits = vec![true, true, false, true, false, false];
732 let selection = RowSelection::from_boolean_buffer(BooleanBuffer::from(bits.clone()));
733 assert_eq!(selection.row_count(), 3);
734
735 let trimmed = selection.trim();
736 assert!(trimmed.as_mask().is_some());
737 assert_eq!(trimmed.as_mask().unwrap().len(), 4);
738 assert_eq!(trimmed.row_count(), 3);
739
740 let offset = trimmed.clone().offset(1);
741 assert_eq!(offset.row_count(), 2);
742
743 let limited = trimmed.limit(2);
744 assert_eq!(limited.row_count(), 2);
745 }
746}