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