1use super::boolean::{MaskSelection, boolean_mask_from_selectors};
26use super::{MaskRunIter, RowSelection, RowSelectionInner, RowSelector};
27use arrow_buffer::{BooleanBuffer, BooleanBufferBuilder, MutableBuffer, bit_util};
28use std::cmp::Ordering;
29use std::iter::Peekable;
30
31const AND_THEN_DENSE_MASK_MIN_LEN: usize = 8192;
38const AND_THEN_DENSE_MASK_MAX_DROPPED_FRACTION: usize = 4;
39const AND_THEN_DENSE_MASK_MIN_INNER_FRACTION: usize = 20;
40
41pub(super) fn and_then_row_selections(
43 first: &[RowSelector],
44 second: &[RowSelector],
45) -> RowSelection {
46 let mut selectors = vec![];
47 let mut first = first.iter().copied().peekable();
48 let mut second = second.iter().copied().peekable();
49 and_then_iter(&mut selectors, &mut first, &mut second);
50 RowSelection::from_selectors(selectors)
51}
52
53pub(super) fn and_then_selectors_with_mask(
57 first: &[RowSelector],
58 second: &BooleanBuffer,
59) -> RowSelection {
60 let mut selectors = vec![];
61 let mut first = first.iter().copied().peekable();
62 let mut second = MaskRunIter::new(second).peekable();
63 and_then_iter(&mut selectors, &mut first, &mut second);
64 RowSelection::from_selectors(selectors)
65}
66
67fn and_then_iter<I, J>(
68 selectors: &mut Vec<RowSelector>,
69 first: &mut Peekable<I>,
70 second: &mut Peekable<J>,
71) where
72 I: Iterator<Item = RowSelector>,
73 J: Iterator<Item = RowSelector>,
74{
75 let mut to_skip = 0;
76 while let Some(b) = second.peek_mut() {
77 let a = first
78 .peek_mut()
79 .expect("selection exceeds the number of selected rows");
80
81 if b.row_count == 0 {
82 second.next().unwrap();
83 continue;
84 }
85
86 if a.row_count == 0 {
87 first.next().unwrap();
88 continue;
89 }
90
91 if a.skip {
92 to_skip += a.row_count;
94 first.next().unwrap();
95 continue;
96 }
97
98 let skip = b.skip;
99 let to_process = a.row_count.min(b.row_count);
100
101 a.row_count -= to_process;
102 b.row_count -= to_process;
103
104 match skip {
105 true => to_skip += to_process,
106 false => {
107 if to_skip != 0 {
108 selectors.push(RowSelector::skip(to_skip));
109 to_skip = 0;
110 }
111 selectors.push(RowSelector::select(to_process))
112 }
113 }
114 }
115
116 for v in first {
117 if v.row_count != 0 {
118 assert!(
119 v.skip,
120 "selection contains less than the number of selected rows"
121 );
122 to_skip += v.row_count
123 }
124 }
125
126 if to_skip != 0 {
127 selectors.push(RowSelector::skip(to_skip));
128 }
129}
130
131pub(super) fn intersect_row_selections(
138 left: &[RowSelector],
139 right: &[RowSelector],
140) -> RowSelection {
141 let mut l_iter = left.iter().copied().peekable();
142 let mut r_iter = right.iter().copied().peekable();
143
144 let iter = std::iter::from_fn(move || {
145 loop {
146 let l = l_iter.peek_mut();
147 let r = r_iter.peek_mut();
148
149 match (l, r) {
150 (Some(a), _) if a.row_count == 0 => {
151 l_iter.next().unwrap();
152 }
153 (_, Some(b)) if b.row_count == 0 => {
154 r_iter.next().unwrap();
155 }
156 (Some(l), Some(r)) => {
157 return match (l.skip, r.skip) {
158 (false, false) => {
160 if l.row_count < r.row_count {
161 r.row_count -= l.row_count;
162 l_iter.next()
163 } else {
164 l.row_count -= r.row_count;
165 r_iter.next()
166 }
167 }
168 _ => {
170 if l.row_count < r.row_count {
171 let skip = l.row_count;
172 r.row_count -= l.row_count;
173 l_iter.next();
174 Some(RowSelector::skip(skip))
175 } else {
176 let skip = r.row_count;
177 l.row_count -= skip;
178 r_iter.next();
179 Some(RowSelector::skip(skip))
180 }
181 }
182 };
183 }
184 (Some(_), None) => return l_iter.next(),
185 (None, Some(_)) => return r_iter.next(),
186 (None, None) => return None,
187 }
188 }
189 });
190
191 iter.collect()
192}
193
194pub(super) fn union_row_selections(left: &[RowSelector], right: &[RowSelector]) -> RowSelection {
203 let mut l_iter = left.iter().copied().peekable();
204 let mut r_iter = right.iter().copied().peekable();
205
206 let iter = std::iter::from_fn(move || {
207 loop {
208 let l = l_iter.peek_mut();
209 let r = r_iter.peek_mut();
210
211 match (l, r) {
212 (Some(a), _) if a.row_count == 0 => {
213 l_iter.next().unwrap();
214 }
215 (_, Some(b)) if b.row_count == 0 => {
216 r_iter.next().unwrap();
217 }
218 (Some(l), Some(r)) => {
219 return match (l.skip, r.skip) {
220 (true, true) => {
222 if l.row_count < r.row_count {
223 let skip = l.row_count;
224 r.row_count -= l.row_count;
225 l_iter.next();
226 Some(RowSelector::skip(skip))
227 } else {
228 let skip = r.row_count;
229 l.row_count -= skip;
230 r_iter.next();
231 Some(RowSelector::skip(skip))
232 }
233 }
234 (false, true) => {
236 if l.row_count < r.row_count {
237 r.row_count -= l.row_count;
238 l_iter.next()
239 } else {
240 let r_row_count = r.row_count;
241 l.row_count -= r_row_count;
242 r_iter.next();
243 Some(RowSelector::select(r_row_count))
244 }
245 }
246 (true, false) => {
248 if l.row_count < r.row_count {
249 let l_row_count = l.row_count;
250 r.row_count -= l_row_count;
251 l_iter.next();
252 Some(RowSelector::select(l_row_count))
253 } else {
254 l.row_count -= r.row_count;
255 r_iter.next()
256 }
257 }
258 _ => {
260 if l.row_count < r.row_count {
261 r.row_count -= l.row_count;
262 l_iter.next()
263 } else {
264 l.row_count -= r.row_count;
265 r_iter.next()
266 }
267 }
268 };
269 }
270 (Some(_), None) => return l_iter.next(),
271 (None, Some(_)) => return r_iter.next(),
272 (None, None) => return None,
273 }
274 }
275 });
276
277 iter.collect()
278}
279
280pub(super) fn combine_mixed_selection(
282 selectors: &[RowSelector],
283 mask: &MaskSelection,
284 op: impl FnOnce(&BooleanBuffer, &BooleanBuffer) -> BooleanBuffer,
285) -> RowSelection {
286 if selectors.is_empty() {
288 return RowSelection::from_mask_selection(mask.clone());
289 }
290 if mask.mask().is_empty() {
291 return RowSelection::from_selectors(selectors.to_vec());
292 }
293 let selectors = boolean_mask_from_selectors(selectors);
294 RowSelection::from_boolean_buffer(op(mask.mask(), &selectors))
295}
296
297pub(super) fn intersect_masks(l: &BooleanBuffer, r: &BooleanBuffer) -> BooleanBuffer {
299 if l.len() == r.len() {
300 return combine_equal_length_masks(l, r, |a, b| a & b);
301 }
302 combine_unequal_length_masks(l, r, |a, b| a & b)
303}
304
305pub(super) fn union_masks(l: &BooleanBuffer, r: &BooleanBuffer) -> BooleanBuffer {
307 if l.len() == r.len() {
308 return combine_equal_length_masks(l, r, |a, b| a | b);
309 }
310 combine_unequal_length_masks(l, r, |a, b| a | b)
311}
312
313fn combine_equal_length_masks<F>(l: &BooleanBuffer, r: &BooleanBuffer, op: F) -> BooleanBuffer
321where
322 F: FnMut(u64, u64) -> u64,
323{
324 BooleanBuffer::from_bitwise_binary_op(
325 l.values(),
326 l.offset(),
327 r.values(),
328 r.offset(),
329 l.len(),
330 op,
331 )
332}
333
334fn combine_unequal_length_masks<F>(l: &BooleanBuffer, r: &BooleanBuffer, op: F) -> BooleanBuffer
348where
349 F: FnMut(u64, u64) -> u64,
350{
351 let (longer, shorter) = if l.len() > r.len() { (l, r) } else { (r, l) };
352
353 let sub_byte_offset = longer.offset() % 8;
354 let start_byte = longer.offset() / 8;
355 let end_byte = bit_util::ceil(longer.offset() + longer.len(), 8);
356 let bytes = &longer.values()[start_byte..end_byte];
357 let mut buffer = MutableBuffer::new(bytes.len());
358 buffer.extend_from_slice(bytes);
359
360 bit_util::apply_bitwise_binary_op(
361 buffer.as_slice_mut(),
362 sub_byte_offset,
363 shorter.values(),
364 shorter.offset(),
365 shorter.len(),
366 op,
367 );
368
369 BooleanBuffer::new(buffer.into(), sub_byte_offset, longer.len())
370}
371
372pub(super) fn and_then_mask(mask: &BooleanBuffer, other: &RowSelection) -> BooleanBuffer {
374 match &other.inner {
375 RowSelectionInner::Mask(other_mask) => and_then_masks(mask, other_mask.mask()),
376 RowSelectionInner::Selectors(selectors) => {
377 and_then_mask_from_selectors(mask, selectors.iter().copied())
378 }
379 }
380}
381
382fn and_then_mask_from_selectors<I>(mask: &BooleanBuffer, other: I) -> BooleanBuffer
383where
384 I: IntoIterator<Item = RowSelector>,
385{
386 let mut builder = BooleanBufferBuilder::new(mask.len());
387 let mut other_iter = other.into_iter();
388 let mut current = other_iter.next();
389 let mut cursor = 0usize;
390
391 for set_idx in mask.set_indices() {
394 if set_idx > cursor {
395 builder.append_n(set_idx - cursor, false);
396 }
397 cursor = set_idx + 1;
398
399 while current.as_ref().is_some_and(|s| s.row_count == 0) {
400 current = other_iter.next();
401 }
402 let selector = current
403 .as_mut()
404 .expect("selection contains less than the number of selected rows");
405 let selected = !selector.skip;
406 selector.row_count -= 1;
407 builder.append(selected);
408 }
409 if cursor < mask.len() {
410 builder.append_n(mask.len() - cursor, false);
411 }
412
413 if current.is_some_and(|s| s.row_count != 0) || other_iter.any(|s| s.row_count != 0) {
414 panic!("selection exceeds the number of selected rows");
415 }
416
417 builder.finish()
418}
419
420fn and_then_masks(mask: &BooleanBuffer, other: &BooleanBuffer) -> BooleanBuffer {
421 let selected_count = mask.count_set_bits();
422 match other.len().cmp(&selected_count) {
423 Ordering::Less => panic!("selection contains less than the number of selected rows"),
424 Ordering::Greater => panic!("selection exceeds the number of selected rows"),
425 Ordering::Equal => {}
426 }
427
428 let other_true_count = other.count_set_bits();
429 if other_true_count == 0 {
430 return BooleanBuffer::new_unset(mask.len());
431 }
432 if other_true_count == selected_count {
433 return mask.clone();
434 }
435
436 if should_use_dense_mask(mask.len(), selected_count, other_true_count) {
437 and_then_dense_masks(mask, other)
438 } else {
439 and_then_sparse_masks(mask, other)
440 }
441}
442
443#[inline]
445fn should_use_dense_mask(mask_len: usize, selected_count: usize, other_true_count: usize) -> bool {
446 mask_len >= AND_THEN_DENSE_MASK_MIN_LEN
447 && mask_len - selected_count <= mask_len.div_ceil(AND_THEN_DENSE_MASK_MAX_DROPPED_FRACTION)
448 && other_true_count >= selected_count / AND_THEN_DENSE_MASK_MIN_INNER_FRACTION
449}
450
451fn and_then_sparse_masks(mask: &BooleanBuffer, other: &BooleanBuffer) -> BooleanBuffer {
454 debug_assert_eq!(other.len(), mask.count_set_bits());
455
456 let mut builder = BooleanBufferBuilder::new(mask.len());
457 let mut outer_set_indices = mask.set_indices();
458 let mut next_selected_ordinal = 0usize;
459 let mut cursor = 0usize;
460
461 for selected_ordinal in other.set_indices() {
462 let skip = selected_ordinal - next_selected_ordinal;
463 let set_idx = outer_set_indices
464 .nth(skip)
465 .expect("validated other length matches selected row count");
466 if set_idx > cursor {
467 builder.append_n(set_idx - cursor, false);
468 }
469 builder.append(true);
470 cursor = set_idx + 1;
471 next_selected_ordinal = selected_ordinal + 1;
472 }
473
474 if cursor < mask.len() {
475 builder.append_n(mask.len() - cursor, false);
476 }
477
478 builder.finish()
479}
480
481#[inline(never)]
484fn and_then_dense_masks(mask: &BooleanBuffer, other: &BooleanBuffer) -> BooleanBuffer {
485 debug_assert_eq!(other.len(), mask.count_set_bits());
486
487 let mut other_chunks = other.bit_chunks().iter_padded();
488 let mut other_remaining = other.len();
489 let mut pending = 0_u128;
490 let mut pending_len = 0;
491 let mut output = MutableBuffer::with_capacity(mask.len().div_ceil(8));
492
493 for mask_word in mask
494 .bit_chunks()
495 .iter_padded()
496 .take(mask.len().div_ceil(64))
497 {
498 let selected = mask_word.count_ones() as usize;
499 while pending_len < selected {
500 let chunk = other_chunks
501 .next()
502 .expect("validated other length matches selected row count");
503 let chunk_len = other_remaining.min(64);
504 pending |= (chunk as u128) << pending_len;
505 pending_len += chunk_len;
506 other_remaining -= chunk_len;
507 }
508
509 let values = pending as u64;
510 output.extend_from_slice(&bit_util::expand(values, mask_word).to_le_bytes());
511 pending >>= selected;
512 pending_len -= selected;
513 }
514
515 debug_assert_eq!(other_remaining, 0);
516 debug_assert_eq!(pending_len, 0);
517 output.truncate(mask.len().div_ceil(8));
518 BooleanBuffer::new(output.into(), 0, mask.len())
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524 use arrow_array::BooleanArray;
525 use rand::{RngExt, SeedableRng, rng, rngs::StdRng};
526
527 #[test]
528 fn test_and() {
529 let mut a = RowSelection::from(vec![
530 RowSelector::skip(12),
531 RowSelector::select(23),
532 RowSelector::skip(3),
533 RowSelector::select(5),
534 ]);
535
536 let b = RowSelection::from(vec![
537 RowSelector::select(5),
538 RowSelector::skip(4),
539 RowSelector::select(15),
540 RowSelector::skip(4),
541 ]);
542
543 let mut expected = RowSelection::from(vec![
544 RowSelector::skip(12),
545 RowSelector::select(5),
546 RowSelector::skip(4),
547 RowSelector::select(14),
548 RowSelector::skip(3),
549 RowSelector::select(1),
550 RowSelector::skip(4),
551 ]);
552
553 assert_eq!(a.and_then(&b), expected);
554
555 a.split_off(7);
556 expected.split_off(7);
557 assert_eq!(a.and_then(&b), expected);
558
559 let a = RowSelection::from(vec![RowSelector::select(5), RowSelector::skip(3)]);
560
561 let b = RowSelection::from(vec![
562 RowSelector::select(2),
563 RowSelector::skip(1),
564 RowSelector::select(1),
565 RowSelector::skip(1),
566 ]);
567
568 assert_eq!(
569 a.and_then(&b).selectors(),
570 vec![
571 RowSelector::select(2),
572 RowSelector::skip(1),
573 RowSelector::select(1),
574 RowSelector::skip(4)
575 ]
576 );
577 }
578
579 #[test]
580 #[should_panic(expected = "selection exceeds the number of selected rows")]
581 fn test_and_longer() {
582 let a = RowSelection::from(vec![
583 RowSelector::select(3),
584 RowSelector::skip(33),
585 RowSelector::select(3),
586 RowSelector::skip(33),
587 ]);
588 let b = RowSelection::from(vec![RowSelector::select(36)]);
589 a.and_then(&b);
590 }
591
592 #[test]
593 #[should_panic(expected = "selection contains less than the number of selected rows")]
594 fn test_and_shorter() {
595 let a = RowSelection::from(vec![
596 RowSelector::select(3),
597 RowSelector::skip(33),
598 RowSelector::select(3),
599 RowSelector::skip(33),
600 ]);
601 let b = RowSelection::from(vec![RowSelector::select(3)]);
602 a.and_then(&b);
603 }
604
605 #[test]
606 fn test_intersect_row_selection_and_combine() {
607 let a = vec![
609 RowSelector::select(5),
610 RowSelector::skip(4),
611 RowSelector::select(1),
612 ];
613 let b = vec![
614 RowSelector::select(8),
615 RowSelector::skip(1),
616 RowSelector::select(1),
617 ];
618
619 let res = intersect_row_selections(&a, &b);
620 assert_eq!(
621 res.selectors(),
622 vec![
623 RowSelector::select(5),
624 RowSelector::skip(4),
625 RowSelector::select(1),
626 ],
627 );
628
629 let a = vec![
631 RowSelector::select(3),
632 RowSelector::skip(33),
633 RowSelector::select(3),
634 RowSelector::skip(33),
635 ];
636 let b = vec![RowSelector::select(36), RowSelector::skip(36)];
637 let res = intersect_row_selections(&a, &b);
638 assert_eq!(
639 res.selectors(),
640 vec![RowSelector::select(3), RowSelector::skip(69)]
641 );
642
643 let a = vec![RowSelector::select(3), RowSelector::skip(7)];
645 let b = vec![
646 RowSelector::select(2),
647 RowSelector::skip(2),
648 RowSelector::select(2),
649 RowSelector::skip(2),
650 RowSelector::select(2),
651 ];
652 let res = intersect_row_selections(&a, &b);
653 assert_eq!(
654 res.selectors(),
655 vec![RowSelector::select(2), RowSelector::skip(8)]
656 );
657
658 let a = vec![RowSelector::select(3), RowSelector::skip(7)];
659 let b = vec![
660 RowSelector::select(2),
661 RowSelector::skip(2),
662 RowSelector::select(2),
663 RowSelector::skip(2),
664 RowSelector::select(2),
665 ];
666 let res = intersect_row_selections(&a, &b);
667 assert_eq!(
668 res.selectors(),
669 vec![RowSelector::select(2), RowSelector::skip(8)]
670 );
671 }
672
673 #[test]
674 #[cfg_attr(miri, ignore)] fn test_and_fuzz() {
676 let mut rand = rng();
677 for _ in 0..100 {
678 let a_len = rand.random_range(10..100);
679 let a_bools: Vec<_> = (0..a_len).map(|_| rand.random_bool(0.2)).collect();
680 let a = RowSelection::from_filters(&[BooleanArray::from(a_bools.clone())]);
681
682 let b_len: usize = a_bools.iter().map(|x| *x as usize).sum();
683 let b_bools: Vec<_> = (0..b_len).map(|_| rand.random_bool(0.8)).collect();
684 let b = RowSelection::from_filters(&[BooleanArray::from(b_bools.clone())]);
685
686 let mut expected_bools = vec![false; a_len];
687
688 let mut iter_b = b_bools.iter();
689 for (idx, b) in a_bools.iter().enumerate() {
690 if *b && *iter_b.next().unwrap() {
691 expected_bools[idx] = true;
692 }
693 }
694
695 let expected = RowSelection::from_filters(&[BooleanArray::from(expected_bools)]);
696
697 assert_eq!(a_len, expected.total_row_count());
698
699 assert_eq!(a.and_then(&b), expected);
700 }
701 }
702
703 #[test]
704 fn test_intersection() {
705 let selection = RowSelection::from(vec![RowSelector::select(1048576)]);
706 let result = selection.intersection(&selection);
707 assert_eq!(result, selection);
708
709 let a = RowSelection::from(vec![
710 RowSelector::skip(10),
711 RowSelector::select(10),
712 RowSelector::skip(10),
713 RowSelector::select(20),
714 ]);
715
716 let b = RowSelection::from(vec![
717 RowSelector::skip(20),
718 RowSelector::select(20),
719 RowSelector::skip(10),
720 ]);
721
722 let result = a.intersection(&b);
723 assert_eq!(
724 result.selectors(),
725 vec![
726 RowSelector::skip(30),
727 RowSelector::select(10),
728 RowSelector::skip(10)
729 ]
730 );
731 }
732
733 #[test]
734 fn test_union() {
735 let selection = RowSelection::from(vec![RowSelector::select(1048576)]);
736 let result = selection.union(&selection);
737 assert_eq!(result, selection);
738
739 let a = RowSelection::from(vec![
741 RowSelector::skip(10),
742 RowSelector::select(10),
743 RowSelector::skip(10),
744 RowSelector::select(20),
745 ]);
746
747 let b = RowSelection::from(vec![
749 RowSelector::skip(20),
750 RowSelector::select(20),
751 RowSelector::skip(10),
752 RowSelector::select(10),
753 RowSelector::skip(10),
754 ]);
755
756 let result = a.union(&b);
757
758 assert_eq!(
760 result.iter().copied().collect::<Vec<_>>(),
761 vec![
762 RowSelector::skip(10),
763 RowSelector::select(50),
764 RowSelector::skip(10),
765 ]
766 );
767 }
768
769 #[test]
770 fn test_mask_and_then_preserves_backing() {
771 let outer_bits = vec![false, true, true, false, true, false, true];
772 let inner_bits = vec![true, false, true, false];
773 let outer_mask = RowSelection::from_boolean_buffer(BooleanBuffer::from(outer_bits.clone()));
774 let inner = RowSelection::from_filters(&[BooleanArray::from(inner_bits.clone())]);
775
776 let result = outer_mask.and_then(&inner);
777 assert!(result.as_mask().is_some());
778
779 let outer_selectors = RowSelection::from_filters(&[BooleanArray::from(outer_bits)]);
780 let expected = outer_selectors.and_then(&inner);
781 assert_eq!(result, expected);
782
783 let result_mask = result.as_mask().unwrap();
784 let actual_bits: Vec<_> = (0..result_mask.len())
785 .map(|i| result_mask.value(i))
786 .collect();
787 assert_eq!(
788 actual_bits,
789 vec![false, true, false, false, true, false, false]
790 );
791 }
792
793 #[test]
794 fn test_mask_and_then_mask_preserves_backing() {
795 let outer_bits = vec![false, true, true, false, true, false, true, true];
796 let inner_bits = vec![false, true, false, true, false];
797 let outer_mask = RowSelection::from_boolean_buffer(BooleanBuffer::from(outer_bits.clone()));
798 let inner_mask = RowSelection::from_boolean_buffer(BooleanBuffer::from(inner_bits));
799
800 let result = outer_mask.and_then(&inner_mask);
801 assert!(result.as_mask().is_some());
802
803 let outer_selectors = RowSelection::from_filters(&[BooleanArray::from(outer_bits)]);
804 let inner_selectors = RowSelection::from_filters(&[BooleanArray::from(vec![
805 false, true, false, true, false,
806 ])]);
807 assert_eq!(result, outer_selectors.and_then(&inner_selectors));
808
809 let result_mask = result.as_mask().unwrap();
810 let actual_bits: Vec<_> = (0..result_mask.len())
811 .map(|i| result_mask.value(i))
812 .collect();
813 assert_eq!(
814 actual_bits,
815 vec![false, false, true, false, false, false, true, false]
816 );
817 }
818
819 struct AndThenTest {
820 outer: BooleanBuffer,
821 inner: BooleanBuffer,
822 dense_mask_expected: bool,
823 }
824
825 impl AndThenTest {
826 fn run(self) {
827 let Self {
828 outer,
829 inner,
830 dense_mask_expected,
831 } = self;
832 assert_eq!(inner.len(), outer.count_set_bits());
833 assert_eq!(
834 should_use_dense_mask(outer.len(), inner.len(), inner.count_set_bits()),
835 dense_mask_expected
836 );
837
838 let mut inner_idx = 0;
839 let expected = BooleanBuffer::from_iter((0..outer.len()).map(|i| {
840 if !outer.value(i) {
841 return false;
842 }
843 let value = inner.value(inner_idx);
844 inner_idx += 1;
845 value
846 }));
847
848 if dense_mask_expected {
849 assert_eq!(and_then_dense_masks(&outer, &inner), expected);
850 }
851
852 let outer = RowSelection::from_boolean_buffer(outer);
853 let inner = RowSelection::from_boolean_buffer(inner);
854 let actual = outer.and_then(&inner);
855 assert_eq!(actual.as_mask().unwrap(), &expected);
856 }
857 }
858
859 #[test]
860 fn test_dense_mask_and_then_mask_with_offsets() {
861 for len in [8192, 8193, 10_000] {
862 for outer_stride in [100, 20, 4] {
863 let outer_offset = 3;
864 let outer = BooleanBuffer::from_iter(
865 (0..len + outer_offset).map(|i| (i + 1) % outer_stride != 0),
866 )
867 .slice(outer_offset, len);
868
869 let inner_offset = 5;
870 let inner_len = outer.count_set_bits();
871 let inner = BooleanBuffer::from_iter(
872 (0..inner_len + inner_offset).map(|i| (i + 2) % 97 != 0),
873 )
874 .slice(inner_offset, inner_len);
875
876 AndThenTest {
877 outer,
878 inner,
879 dense_mask_expected: true,
880 }
881 .run();
882 }
883 }
884 }
885
886 #[test]
887 fn test_dense_mask_and_then_mask_randomized_word_boundaries() {
888 let mut rng = StdRng::seed_from_u64(0x67e4_a91b_239d_c805);
889
890 for (len, outer_offset, inner_offset) in [(8192, 0, 0), (8192, 3, 5), (8193, 7, 1)] {
891 let outer =
892 BooleanBuffer::from_iter((0..len + outer_offset).map(|_| rng.random_bool(0.8)))
893 .slice(outer_offset, len);
894 let inner_len = outer.count_set_bits();
895 let inner = BooleanBuffer::from_iter(
896 (0..inner_len + inner_offset).map(|_| rng.random_bool(0.5)),
897 )
898 .slice(inner_offset, inner_len);
899
900 AndThenTest {
901 outer,
902 inner,
903 dense_mask_expected: true,
904 }
905 .run();
906 }
907 }
908
909 #[test]
910 fn test_dense_mask_and_then_policy() {
911 let len = 8192;
912 let selected = len * 3 / 4;
913 let min_inner = selected / AND_THEN_DENSE_MASK_MIN_INNER_FRACTION;
914
915 assert!(!should_use_dense_mask(len - 1, selected, min_inner));
916 assert!(!should_use_dense_mask(len, selected - 1, min_inner));
917 assert!(!should_use_dense_mask(len, selected, min_inner - 1));
918 assert!(should_use_dense_mask(len, selected, min_inner));
919 }
920
921 #[test]
922 fn test_selector_and_then_mask() {
923 let outer =
924 RowSelection::from_filters(&[BooleanArray::from(vec![false, true, true, false, true])]);
925 let inner = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![true, false, true]));
926
927 let result = outer.and_then(&inner);
928 assert!(result.as_mask().is_none());
929 assert_eq!(
930 result,
931 RowSelection::from_filters(&[BooleanArray::from(vec![
932 false, true, false, false, true,
933 ])])
934 );
935 }
936
937 #[test]
938 fn test_mask_and_then_none_selected_returns_all_unset() {
939 let outer = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
940 false, true, true, false, true,
941 ]));
942 let inner =
943 RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![false, false, false]));
944
945 let result = outer.and_then(&inner);
946 let mask = result.as_mask().unwrap();
947 assert_eq!(mask.len(), 5);
948 assert_eq!(mask.count_set_bits(), 0);
949 }
950
951 #[test]
952 fn test_mask_intersection_uses_bitwise() {
953 let a_bits = vec![true, true, false, true, false, true];
954 let b_bits = vec![true, false, true, true, true, false];
955 let a = RowSelection::from_boolean_buffer(BooleanBuffer::from(a_bits.clone()));
956 let b = RowSelection::from_boolean_buffer(BooleanBuffer::from(b_bits.clone()));
957
958 let r = a.intersection(&b);
959 assert!(r.as_mask().is_some());
960
961 let expected: Vec<bool> = a_bits.iter().zip(&b_bits).map(|(x, y)| *x && *y).collect();
962 let expected_sel = RowSelection::from_filters(&[BooleanArray::from(expected)]);
963 assert_eq!(r, expected_sel);
964 }
965
966 #[test]
967 fn test_mask_union_uses_bitwise() {
968 let a_bits = vec![true, false, false, true, false, false];
969 let b_bits = vec![false, true, false, false, true, false];
970 let a = RowSelection::from_boolean_buffer(BooleanBuffer::from(a_bits.clone()));
971 let b = RowSelection::from_boolean_buffer(BooleanBuffer::from(b_bits.clone()));
972
973 let r = a.union(&b);
974 assert!(r.as_mask().is_some());
975
976 let expected: Vec<bool> = a_bits.iter().zip(&b_bits).map(|(x, y)| *x || *y).collect();
977 let expected_sel = RowSelection::from_filters(&[BooleanArray::from(expected)]);
978 assert_eq!(r, expected_sel);
979 }
980
981 #[test]
982 fn test_mixed_mask_selector_intersection_and_union() {
983 let mask_bits = vec![true, false, true, false, true, false];
984 let selector_bits = vec![false, true, true, false, false, true];
985 let mask = RowSelection::from_boolean_buffer(BooleanBuffer::from(mask_bits.clone()));
986 let selectors = RowSelection::from_filters(&[BooleanArray::from(selector_bits.clone())]);
987
988 let intersection_bits: Vec<_> = mask_bits
989 .iter()
990 .zip(&selector_bits)
991 .map(|(x, y)| *x && *y)
992 .collect();
993 let expected_intersection =
994 RowSelection::from_filters(&[BooleanArray::from(intersection_bits)]);
995 for result in [mask.intersection(&selectors), selectors.intersection(&mask)] {
996 assert!(result.as_mask().is_some());
997 assert_eq!(result, expected_intersection);
998 }
999
1000 let union_bits: Vec<_> = mask_bits
1001 .iter()
1002 .zip(&selector_bits)
1003 .map(|(x, y)| *x || *y)
1004 .collect();
1005 let expected_union = RowSelection::from_filters(&[BooleanArray::from(union_bits)]);
1006 for result in [mask.union(&selectors), selectors.union(&mask)] {
1007 assert!(result.as_mask().is_some());
1008 assert_eq!(result, expected_union);
1009 }
1010 }
1011
1012 #[test]
1013 fn test_mask_intersection_uneven_passes_tail_through() {
1014 let a_bits = vec![true, true, true, true, true];
1015 let b_bits = vec![true, false, true];
1016 let a = RowSelection::from_boolean_buffer(BooleanBuffer::from(a_bits));
1017 let b = RowSelection::from_boolean_buffer(BooleanBuffer::from(b_bits));
1018
1019 let r = a.intersection(&b);
1020 let r_mask = r.as_mask().unwrap();
1021 assert_eq!(r_mask.len(), 5);
1022 let bits: Vec<bool> = (0..5).map(|i| r_mask.value(i)).collect();
1023 assert_eq!(bits, vec![true, false, true, true, true]);
1024
1025 let a = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![true, false, true]));
1027 let b = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
1028 true, true, true, false, true,
1029 ]));
1030 let r = a.intersection(&b);
1031 let r_mask = r.as_mask().unwrap();
1032 assert_eq!(r_mask.len(), 5);
1033 let bits: Vec<bool> = (0..5).map(|i| r_mask.value(i)).collect();
1034 assert_eq!(bits, vec![true, false, true, false, true]);
1035 }
1036
1037 #[test]
1038 fn test_mask_union_uneven_passes_tail_through() {
1039 let a_bits = vec![true, false, true];
1040 let b_bits = vec![false, true, false, true, false];
1041 let a = RowSelection::from_boolean_buffer(BooleanBuffer::from(a_bits));
1042 let b = RowSelection::from_boolean_buffer(BooleanBuffer::from(b_bits));
1043
1044 let r = a.union(&b);
1045 let r_mask = r.as_mask().unwrap();
1046 assert_eq!(r_mask.len(), 5);
1047 let bits: Vec<bool> = (0..5).map(|i| r_mask.value(i)).collect();
1048 assert_eq!(bits, vec![true, true, true, true, false]);
1049
1050 let a = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![
1051 false, true, false, false, true,
1052 ]));
1053 let b = RowSelection::from_boolean_buffer(BooleanBuffer::from(vec![true, false, false]));
1054 let r = a.union(&b);
1055 let r_mask = r.as_mask().unwrap();
1056 let bits: Vec<bool> = (0..5).map(|i| r_mask.value(i)).collect();
1057 assert_eq!(bits, vec![true, true, false, false, true]);
1058 }
1059
1060 fn expected_combined(l: &[bool], r: &[bool], op: fn(bool, bool) -> bool) -> Vec<bool> {
1063 let common = l.len().min(r.len());
1064 let longer = if l.len() > r.len() { l } else { r };
1065 (0..common)
1066 .map(|i| op(l[i], r[i]))
1067 .chain(longer[common..].iter().copied())
1068 .collect()
1069 }
1070
1071 fn assert_mask_eq(actual: &BooleanBuffer, expected: &[bool], context: &str) {
1072 assert_eq!(actual.len(), expected.len(), "{context}: length");
1073 let actual: Vec<bool> = actual.iter().collect();
1074 assert_eq!(actual, expected, "{context}");
1075 }
1076
1077 #[test]
1078 fn test_mixed_mask_selector_algebra_with_offsets_and_uneven_lengths() {
1079 for rows in [1, 7, 8, 63, 64, 65, 137] {
1080 for (mask_len, selector_len) in [(rows, rows), (rows, 137), (137, rows)] {
1081 for offset in [0, 1, 7, 63] {
1082 for mask_bits in [
1083 vec![false; mask_len],
1084 vec![true; mask_len],
1085 (0..mask_len).map(|i| i < mask_len / 2).collect(),
1086 (0..mask_len).map(|i| i % 2 == 0).collect(),
1087 ] {
1088 let buffer = BooleanBuffer::from_iter(
1089 std::iter::repeat_n(false, offset).chain(mask_bits.iter().copied()),
1090 )
1091 .slice(offset, mask_len);
1092 let mask = RowSelection::from_boolean_buffer(buffer);
1093 for selector_bits in [
1094 vec![false; selector_len],
1095 vec![true; selector_len],
1096 (0..selector_len).map(|i| i % 2 == 0).collect(),
1097 (0..selector_len).map(|i| (i / 11) % 2 == 0).collect(),
1098 ] {
1099 let selectors = RowSelection::from_filters(&[BooleanArray::from(
1100 selector_bits.clone(),
1101 )]);
1102 let context = format!(
1103 "mask_len={mask_len} selector_len={selector_len} offset={offset}"
1104 );
1105 let intersection =
1106 expected_combined(&mask_bits, &selector_bits, |a, b| a && b);
1107 let union =
1108 expected_combined(&mask_bits, &selector_bits, |a, b| a || b);
1109 for (left, right) in [(&mask, &selectors), (&selectors, &mask)] {
1110 assert_mask_eq(
1111 left.intersection(right).as_mask().unwrap(),
1112 &intersection,
1113 &context,
1114 );
1115 assert_mask_eq(
1116 left.union(right).as_mask().unwrap(),
1117 &union,
1118 &context,
1119 );
1120 }
1121 }
1122 }
1123 }
1124 }
1125 }
1126 }
1127
1128 #[test]
1129 fn test_mixed_algebra_empty_operand_preserves_tail() {
1130 let empty = RowSelection::default();
1131 let buffer = BooleanBuffer::from_iter((0..64).map(|i| i % 3 == 0));
1132 let mask = RowSelection::from_boolean_buffer(buffer.slice(5, 40));
1133 let selectors = RowSelection::from(vec![
1134 RowSelector::skip(3),
1135 RowSelector::select(7),
1136 RowSelector::skip(4),
1137 ]);
1138 let empty_mask = RowSelection::from_boolean_buffer(BooleanBuffer::new_unset(0));
1139 for (left, right, expected) in [
1140 (&empty, &mask, &mask),
1141 (&mask, &empty, &mask),
1142 (&empty_mask, &selectors, &selectors),
1143 (&selectors, &empty_mask, &selectors),
1144 (&empty, &empty_mask, &empty_mask),
1145 (&empty_mask, &empty, &empty_mask),
1146 ] {
1147 for result in [left.intersection(right), left.union(right)] {
1148 assert_eq!(&result, expected);
1149 match (result.as_mask(), expected.as_mask()) {
1150 (Some(actual), Some(expected)) => {
1151 assert_eq!(actual.inner().as_ptr(), expected.inner().as_ptr());
1152 assert_eq!(actual.offset(), expected.offset());
1153 }
1154 (None, None) => {}
1155 _ => panic!("empty operand changed the other operand's representation"),
1156 }
1157 }
1158 }
1159 }
1160
1161 #[test]
1162 #[cfg_attr(miri, ignore)] fn test_mask_algebra_with_offsets() {
1164 let base: Vec<bool> = (0..600).map(|i| i % 7 == 0 || i % 3 == 1).collect();
1168 let other: Vec<bool> = (0..600).map(|i| i % 5 == 2 || i % 11 == 4).collect();
1169 let base = BooleanBuffer::from(base);
1170 let other = BooleanBuffer::from(other);
1171
1172 for l_offset in [0, 1, 5, 8, 13, 64, 67] {
1173 for r_offset in [0, 1, 3, 8, 60, 64, 70] {
1174 for (l_len, r_len) in [
1175 (0, 9),
1176 (9, 0),
1177 (1, 200),
1178 (200, 1),
1179 (63, 130),
1180 (321, 65),
1181 (0, 0),
1182 (1, 1),
1183 (63, 63),
1184 (64, 64),
1185 (200, 200),
1186 (321, 321),
1187 ] {
1188 let l = base.slice(l_offset, l_len);
1189 let r = other.slice(r_offset, r_len);
1190 let l_bits: Vec<bool> = l.iter().collect();
1191 let r_bits: Vec<bool> = r.iter().collect();
1192 let context =
1193 format!("l_offset={l_offset} r_offset={r_offset} lens=({l_len},{r_len})");
1194
1195 assert_mask_eq(
1196 &intersect_masks(&l, &r),
1197 &expected_combined(&l_bits, &r_bits, |a, b| a && b),
1198 &format!("intersect {context}"),
1199 );
1200 assert_mask_eq(
1201 &union_masks(&l, &r),
1202 &expected_combined(&l_bits, &r_bits, |a, b| a || b),
1203 &format!("union {context}"),
1204 );
1205 }
1206 }
1207 }
1208 }
1209
1210 #[test]
1211 #[cfg_attr(miri, ignore)] fn test_mask_algebra_does_not_retain_backing_buffer() {
1213 let long = BooleanBuffer::from((0..80_000).map(|i| i % 3 == 0).collect::<Vec<bool>>());
1218 assert!(long.inner().capacity() >= 10_000);
1219
1220 for (l, r) in [
1221 (long.slice(5, 40), BooleanBuffer::new_unset(0)),
1222 (long.slice(5, 40), BooleanBuffer::new_set(7)),
1223 (BooleanBuffer::new_set(7), long.slice(5, 40)),
1224 ] {
1225 for combined in [intersect_masks(&l, &r), union_masks(&l, &r)] {
1226 assert!(
1227 combined.inner().capacity() < long.inner().capacity(),
1228 "result retained the original backing allocation"
1229 );
1230 }
1231 }
1232 }
1233
1234 #[test]
1235 #[cfg_attr(miri, ignore)] fn test_mask_algebra_fuzz() {
1237 let mut rng = rng();
1238 for _ in 0..200 {
1239 let l_offset = rng.random_range(0..70);
1240 let r_offset = rng.random_range(0..70);
1241 let l_len = rng.random_range(0..300);
1242 let r_len = match rng.random_bool(0.25) {
1244 true => l_len,
1245 false => rng.random_range(0..300),
1246 };
1247
1248 let l_bits: Vec<bool> = (0..l_offset + l_len)
1249 .map(|_| rng.random_bool(0.5))
1250 .collect();
1251 let r_bits: Vec<bool> = (0..r_offset + r_len)
1252 .map(|_| rng.random_bool(0.5))
1253 .collect();
1254 let l = BooleanBuffer::from(l_bits).slice(l_offset, l_len);
1255 let r = BooleanBuffer::from(r_bits).slice(r_offset, r_len);
1256 let l_bits: Vec<bool> = l.iter().collect();
1257 let r_bits: Vec<bool> = r.iter().collect();
1258
1259 assert_mask_eq(
1260 &intersect_masks(&l, &r),
1261 &expected_combined(&l_bits, &r_bits, |a, b| a && b),
1262 "intersect",
1263 );
1264 assert_mask_eq(
1265 &union_masks(&l, &r),
1266 &expected_combined(&l_bits, &r_bits, |a, b| a || b),
1267 "union",
1268 );
1269 }
1270 }
1271
1272 #[test]
1273 fn dense_composition_with_zero_words_and_offsets() {
1274 for mask_len in [8192, 8193, 65537] {
1275 for (mask_offset, inner_offset) in [(0, 0), (3, 5), (63, 65), (65, 129)] {
1276 for stride in [4, 100] {
1277 let mask =
1278 BooleanBuffer::from_iter((0..mask_offset + mask_len + 73).map(|i| {
1279 !(mask_offset..mask_offset + mask_len).contains(&i)
1280 || (i - mask_offset) % stride != 0
1281 }))
1282 .slice(mask_offset, mask_len);
1283 let len = mask.count_set_bits();
1284 for start in [0, 63, len / 2] {
1285 for select_last in [false, true] {
1286 let count = len / 10;
1287 let inner =
1288 BooleanBuffer::from_iter((0..inner_offset + len + 73).map(|i| {
1289 if !(inner_offset..inner_offset + len).contains(&i) {
1290 return true;
1291 }
1292 let j = i - inner_offset;
1293 (start..start + count).contains(&j)
1294 || select_last && j == len - 1
1295 }))
1296 .slice(inner_offset, len);
1297 AndThenTest {
1298 outer: mask.clone(),
1299 inner,
1300 dense_mask_expected: true,
1301 }
1302 .run();
1303 }
1304 }
1305 }
1306 }
1307 }
1308 }
1309}