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