1use lance_core::deepsize::DeepSizeOf;
5
6use super::{RowAddrMask, RowAddrTreeMap, RowSetOps};
7
8#[derive(Clone, Debug, Default, DeepSizeOf)]
18pub struct NullableRowAddrSet {
19 selected: RowAddrTreeMap,
20 nulls: RowAddrTreeMap,
22}
23
24impl NullableRowAddrSet {
25 pub fn new(selected: RowAddrTreeMap, nulls: RowAddrTreeMap) -> Self {
30 Self { selected, nulls }
31 }
32
33 pub fn with_nulls(mut self, nulls: RowAddrTreeMap) -> Self {
34 self.nulls = nulls;
35 self
36 }
37
38 pub fn empty() -> Self {
40 Default::default()
41 }
42
43 pub fn len(&self) -> Option<u64> {
48 self.true_rows().len()
49 }
50
51 pub fn is_empty(&self) -> bool {
52 self.selected.is_empty()
53 }
54
55 pub fn selected(&self, row_id: u64) -> bool {
57 self.selected.contains(row_id) && !self.nulls.contains(row_id)
58 }
59
60 pub fn null_rows(&self) -> &RowAddrTreeMap {
62 &self.nulls
63 }
64
65 pub fn selected_rows(&self) -> &RowAddrTreeMap {
73 &self.selected
74 }
75
76 pub fn true_rows(&self) -> RowAddrTreeMap {
78 self.selected.clone() - self.nulls.clone()
79 }
80
81 pub fn union_all(selections: &[Self]) -> Self {
82 let selected = RowAddrTreeMap::union_all(
83 &selections
84 .iter()
85 .map(|s| &s.selected)
86 .collect::<Vec<&RowAddrTreeMap>>(),
87 );
88 let nulls = RowAddrTreeMap::union_all(
89 &selections
90 .iter()
91 .map(|s| &s.nulls)
92 .collect::<Vec<&RowAddrTreeMap>>(),
93 );
94 let any_true = selections
97 .iter()
98 .map(|s| s.selected.clone() - &s.nulls)
99 .fold(RowAddrTreeMap::new(), |acc, t| acc | t);
100 let nulls = nulls - &any_true;
101 Self { selected, nulls }
102 }
103}
104
105impl PartialEq for NullableRowAddrSet {
106 fn eq(&self, other: &Self) -> bool {
107 self.true_rows() == other.true_rows() && self.nulls == other.nulls
112 }
113}
114
115impl std::ops::BitAndAssign<&Self> for NullableRowAddrSet {
116 fn bitand_assign(&mut self, rhs: &Self) {
117 self.nulls = if self.nulls.is_empty() && rhs.nulls.is_empty() {
118 RowAddrTreeMap::new() } else {
120 (self.nulls.clone() & &rhs.nulls) | (self.nulls.clone() & &rhs.selected) | (rhs.nulls.clone() & &self.selected) };
124
125 self.selected &= &rhs.selected;
126 }
127}
128
129impl std::ops::BitOrAssign<&Self> for NullableRowAddrSet {
130 fn bitor_assign(&mut self, rhs: &Self) {
131 self.nulls = if self.nulls.is_empty() && rhs.nulls.is_empty() {
132 RowAddrTreeMap::new() } else {
134 let true_rows =
136 (self.selected.clone() - &self.nulls) | (rhs.selected.clone() - &rhs.nulls);
137 (self.nulls.clone() | &rhs.nulls) - true_rows
138 };
139
140 self.selected |= &rhs.selected;
141 }
142}
143
144#[derive(Clone, Debug, PartialEq)]
150pub enum NullableRowAddrMask {
151 AllowList(NullableRowAddrSet),
152 BlockList(NullableRowAddrSet),
153}
154
155impl NullableRowAddrMask {
156 pub fn allow_nothing() -> Self {
158 Self::AllowList(NullableRowAddrSet::empty())
159 }
160
161 pub fn all_rows() -> Self {
163 Self::BlockList(NullableRowAddrSet::empty())
164 }
165
166 pub fn selected(&self, row_id: u64) -> bool {
167 match self {
168 Self::AllowList(NullableRowAddrSet { selected, nulls }) => {
169 selected.contains(row_id) && !nulls.contains(row_id)
170 }
171 Self::BlockList(NullableRowAddrSet { selected, nulls }) => {
172 !selected.contains(row_id) && !nulls.contains(row_id)
173 }
174 }
175 }
176
177 pub fn drop_nulls(self) -> RowAddrMask {
178 match self {
179 Self::AllowList(NullableRowAddrSet { selected, nulls }) => {
180 RowAddrMask::AllowList(selected - nulls)
181 }
182 Self::BlockList(NullableRowAddrSet { selected, nulls }) => {
183 RowAddrMask::BlockList(selected | nulls)
184 }
185 }
186 }
187}
188
189impl std::ops::Not for NullableRowAddrMask {
190 type Output = Self;
191
192 fn not(self) -> Self::Output {
193 match self {
194 Self::AllowList(set) => Self::BlockList(set),
195 Self::BlockList(set) => Self::AllowList(set),
196 }
197 }
198}
199
200impl std::ops::BitAnd for NullableRowAddrMask {
201 type Output = Self;
202
203 fn bitand(self, rhs: Self) -> Self::Output {
204 match (self, rhs) {
209 (Self::AllowList(a), Self::AllowList(b)) => {
210 let nulls = if a.nulls.is_empty() && b.nulls.is_empty() {
211 RowAddrTreeMap::new() } else {
213 (a.nulls.clone() & &b.nulls) | (a.nulls & &b.selected) | (b.nulls & &a.selected) };
217 let selected = a.selected & b.selected;
218 Self::AllowList(NullableRowAddrSet { selected, nulls })
219 }
220 (Self::AllowList(allow), Self::BlockList(block))
221 | (Self::BlockList(block), Self::AllowList(allow)) => {
222 let nulls = if allow.nulls.is_empty() && block.nulls.is_empty() {
223 RowAddrTreeMap::new() } else {
225 (allow.nulls.clone() & &block.nulls) | (allow.nulls - &block.selected) | (block.nulls & &allow.selected) };
229 let selected = allow.selected - block.selected;
230 Self::AllowList(NullableRowAddrSet { selected, nulls })
231 }
232 (Self::BlockList(a), Self::BlockList(b)) => {
233 let nulls = if a.nulls.is_empty() && b.nulls.is_empty() {
234 RowAddrTreeMap::new() } else {
236 (a.nulls.clone() & &b.nulls) | (a.nulls - &b.selected) | (b.nulls - &a.selected) };
240 let selected = a.selected | b.selected;
241 Self::BlockList(NullableRowAddrSet { selected, nulls })
242 }
243 }
244 }
245}
246
247impl std::ops::BitOr for NullableRowAddrMask {
248 type Output = Self;
249
250 fn bitor(self, rhs: Self) -> Self::Output {
251 match (self, rhs) {
256 (Self::AllowList(a), Self::AllowList(b)) => {
257 let nulls = if a.nulls.is_empty() && b.nulls.is_empty() {
258 RowAddrTreeMap::new() } else {
260 let true_rows =
262 (a.selected.clone() - &a.nulls) | (b.selected.clone() - &b.nulls);
263 (a.nulls | b.nulls) - true_rows
264 };
265 let selected = (a.selected | b.selected) | &nulls;
266 Self::AllowList(NullableRowAddrSet { selected, nulls })
267 }
268 (Self::AllowList(allow), Self::BlockList(block))
269 | (Self::BlockList(block), Self::AllowList(allow)) => {
270 let allow_true = allow.selected.clone() - &allow.nulls;
271 let block_false = block.selected.clone() - &block.nulls;
272
273 let nulls = if allow.nulls.is_empty() && block.nulls.is_empty() {
274 RowAddrTreeMap::new() } else {
276 (allow.nulls & &block_false) | (block.nulls - &allow_true)
279 };
280 let selected = (block_false - &allow_true) | &nulls;
281 Self::BlockList(NullableRowAddrSet { selected, nulls })
282 }
283 (Self::BlockList(a), Self::BlockList(b)) => {
284 let a_false = a.selected.clone() - &a.nulls;
285 let b_false = b.selected.clone() - &b.nulls;
286 let nulls = if a.nulls.is_empty() && b.nulls.is_empty() {
287 RowAddrTreeMap::new() } else {
289 (a.nulls.clone() & &b_false)
291 | (b.nulls.clone() & &a_false)
292 | (a.nulls & &b.nulls)
293 };
294 let selected = (a_false & b_false) | &nulls;
295 Self::BlockList(NullableRowAddrSet { selected, nulls })
296 }
297 }
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 fn rows(ids: &[u64]) -> RowAddrTreeMap {
306 RowAddrTreeMap::from_iter(ids)
307 }
308
309 fn nullable_set(selected: &[u64], nulls: &[u64]) -> NullableRowAddrSet {
310 NullableRowAddrSet::new(rows(selected), rows(nulls))
311 }
312
313 fn allow(selected: &[u64], nulls: &[u64]) -> NullableRowAddrMask {
314 NullableRowAddrMask::AllowList(nullable_set(selected, nulls))
315 }
316
317 fn block(selected: &[u64], nulls: &[u64]) -> NullableRowAddrMask {
318 NullableRowAddrMask::BlockList(nullable_set(selected, nulls))
319 }
320
321 fn assert_mask_selects(mask: &NullableRowAddrMask, selected: &[u64], not_selected: &[u64]) {
322 for &id in selected {
323 assert!(mask.selected(id), "Expected row {} to be selected", id);
324 }
325 for &id in not_selected {
326 assert!(!mask.selected(id), "Expected row {} to NOT be selected", id);
327 }
328 }
329
330 #[test]
331 fn test_not_with_nulls() {
332 let mask = allow(&[1, 2], &[2]);
337 let not_mask = !mask;
338
339 assert_mask_selects(¬_mask, &[0], &[1, 2]);
343 }
344
345 #[test]
346 fn test_and_with_nulls() {
347 let true_mask = allow(&[0, 1, 2, 3, 4], &[]);
351 let null_mask = allow(&[0, 1, 2, 3, 4], &[1, 3]);
352 let result = true_mask & null_mask.clone();
353
354 assert_mask_selects(&result, &[0, 2, 4], &[1, 3]);
356
357 let false_mask = block(&[0, 1, 2, 3, 4], &[]);
359 let result = false_mask & null_mask;
360
361 assert_mask_selects(&result, &[], &[0, 1, 2, 3, 4]);
363
364 let mask1 = allow(&[0, 1, 2], &[1]);
366 let mask2 = allow(&[0, 2, 3], &[2]);
367 let result = mask1 & mask2;
368
369 assert_mask_selects(&result, &[0], &[1, 2, 3]);
371 }
372
373 #[test]
374 fn test_or_with_nulls() {
375 let false_mask = block(&[0, 1, 2], &[]);
379 let null_mask = allow(&[0, 1, 2], &[1, 2]);
380 let result = false_mask | null_mask.clone();
381
382 assert_mask_selects(&result, &[0], &[1, 2]);
384
385 let true_mask = allow(&[0, 1, 2], &[]);
387 let result = true_mask | null_mask;
388
389 assert_mask_selects(&result, &[0, 1, 2], &[]);
391
392 let mask1 = block(&[0, 1, 2, 3], &[1, 2]);
394 let mask2 = block(&[0, 1, 2, 3], &[2, 3]);
395 let result = mask1 | mask2;
396
397 assert_mask_selects(&result, &[], &[0, 1, 2, 3]);
399 }
400
401 #[test]
402 fn test_or_allow_block_keeps_block_nulls() {
403 let allow_mask = allow(&[1], &[0]);
406 let block_mask = block(&[], &[0]);
407 let result = allow_mask | block_mask;
408
409 assert_mask_selects(&result, &[1], &[0]);
411 }
412
413 #[test]
414 fn test_or_allow_block_keeps_block_nulls_with_false_rows() {
415 let allow_mask = allow(&[2], &[]);
418 let block_mask = block(&[1], &[0]);
419 let result = allow_mask | block_mask;
420
421 assert_mask_selects(&result, &[2], &[0, 1]);
423 }
424
425 #[test]
426 fn test_or_block_block_true_overrides_null() {
427 let true_mask = block(&[], &[]);
429 let null_mask = block(&[], &[0]);
430 let result = true_mask | null_mask;
431
432 assert_mask_selects(&result, &[0], &[]);
434 }
435
436 #[test]
437 fn test_row_selection_bit_or() {
438 let left = nullable_set(&[1, 2, 3, 4], &[2, 4]);
440 let right = nullable_set(&[3, 4, 5, 6], &[4, 6, 7]);
442 let expected_true = rows(&[1, 3, 5]);
444 let expected_nulls = rows(&[2, 4, 6, 7]);
445
446 let mut result = left.clone();
447 result |= &right;
448 assert_eq!(&result.true_rows(), &expected_true);
449 assert_eq!(result.null_rows(), &expected_nulls);
450
451 let mut result = right.clone();
453 result |= &left;
454 assert_eq!(&result.true_rows(), &expected_true);
455 assert_eq!(result.null_rows(), &expected_nulls);
456 }
457
458 #[test]
459 fn test_row_selection_bit_and() {
460 let left = nullable_set(&[1, 2, 3, 4], &[2, 4]);
462 let right = nullable_set(&[3, 4, 5, 6], &[4, 6, 7]);
464 let expected_true = rows(&[3]);
466 let expected_nulls = rows(&[4]);
467
468 let mut result = left.clone();
469 result &= &right;
470 assert_eq!(&result.true_rows(), &expected_true);
471 assert_eq!(result.null_rows(), &expected_nulls);
472
473 let mut result = right.clone();
475 result &= &left;
476 assert_eq!(&result.true_rows(), &expected_true);
477 assert_eq!(result.null_rows(), &expected_nulls);
478 }
479
480 #[test]
481 fn test_union_all() {
482 let set1 = nullable_set(&[1, 2, 3, 4], &[4, 5, 6]);
485 let set2 = nullable_set(&[1, 4, 7, 8], &[2, 5, 8]);
487 let set3 = NullableRowAddrSet::empty();
488
489 let result = NullableRowAddrSet::union_all(&[set1, set2, set3]);
490
491 assert_eq!(&result.true_rows(), &rows(&[1, 2, 3, 4, 7]));
493 assert_eq!(result.null_rows(), &rows(&[5, 6, 8]));
494 }
495
496 #[test]
497 fn test_partial_eq_semantic_equivalence() {
498 let a = NullableRowAddrSet::new(rows(&[5]), rows(&[5]));
504 let b = NullableRowAddrSet::new(rows(&[]), rows(&[5]));
505 assert_eq!(a, b);
506 assert_eq!(a.true_rows(), b.true_rows());
507 assert_eq!(a.null_rows(), b.null_rows());
508 }
509
510 #[test]
511 fn test_union_all_true_overrides_null() {
512 let set1 = nullable_set(&[5], &[]);
515 let set2 = nullable_set(&[5], &[5]);
516
517 let result = NullableRowAddrSet::union_all(&[set1, set2]);
518
519 assert_eq!(result.true_rows(), rows(&[5]));
520 assert!(result.null_rows().is_empty());
521 }
522
523 #[test]
524 fn test_union_all_null_only_input() {
525 let set1 = NullableRowAddrSet::new(rows(&[]), rows(&[5]));
528 let set2 = NullableRowAddrSet::new(rows(&[1]), rows(&[]));
529
530 let result = NullableRowAddrSet::union_all(&[set1, set2]);
531
532 assert_eq!(result.true_rows(), rows(&[1]));
533 assert_eq!(result.null_rows(), &rows(&[5]));
534 }
535
536 #[test]
537 fn test_union_all_all_null_for_a_row() {
538 let set1 = nullable_set(&[7], &[7]);
540 let set2 = nullable_set(&[7], &[7]);
541 let set3 = NullableRowAddrSet::new(rows(&[]), rows(&[7]));
542
543 let result = NullableRowAddrSet::union_all(&[set1, set2, set3]);
544
545 assert!(result.true_rows().is_empty());
546 assert_eq!(result.null_rows(), &rows(&[7]));
547 }
548
549 #[test]
550 fn test_union_all_empty_inputs() {
551 let result = NullableRowAddrSet::union_all(&[]);
552 assert!(result.true_rows().is_empty());
553 assert!(result.null_rows().is_empty());
554 }
555
556 #[test]
557 fn test_union_all_single_input() {
558 let set = nullable_set(&[1, 2, 3, 4], &[2, 4]);
560 let result = NullableRowAddrSet::union_all(std::slice::from_ref(&set));
561
562 assert_eq!(result.true_rows(), rows(&[1, 3]));
563 assert_eq!(result.null_rows(), &rows(&[2, 4]));
564 }
565
566 #[test]
567 fn test_union_all_all_empty_inputs() {
568 let inputs = [
569 NullableRowAddrSet::empty(),
570 NullableRowAddrSet::empty(),
571 NullableRowAddrSet::empty(),
572 ];
573 let result = NullableRowAddrSet::union_all(&inputs);
574 assert!(result.true_rows().is_empty());
575 assert!(result.null_rows().is_empty());
576 }
577
578 #[test]
579 fn test_union_all_disjoint_inputs() {
580 let set1 = nullable_set(&[1, 2], &[2]);
582 let set2 = nullable_set(&[10, 11], &[11]);
583 let set3 = nullable_set(&[20], &[]);
584
585 let result = NullableRowAddrSet::union_all(&[set1, set2, set3]);
586
587 assert_eq!(result.true_rows(), rows(&[1, 10, 20]));
588 assert_eq!(result.null_rows(), &rows(&[2, 11]));
589 }
590
591 #[test]
592 fn test_union_all_three_state_row() {
593 let set1 = nullable_set(&[42], &[]);
597 let set2 = nullable_set(&[42], &[42]);
598 let set3 = NullableRowAddrSet::empty();
599
600 let result = NullableRowAddrSet::union_all(&[set1, set2, set3]);
601
602 assert_eq!(result.true_rows(), rows(&[42]));
603 assert!(result.null_rows().is_empty());
604 }
605
606 #[test]
607 fn test_union_all_matches_repeated_bitor() {
608 let set1 = nullable_set(&[1, 2, 3, 4], &[4, 5, 6]);
611 let set2 = nullable_set(&[1, 4, 7, 8], &[2, 5, 8]);
612 let set3 = nullable_set(&[2, 6, 10], &[6, 10]);
613
614 let via_union_all =
615 NullableRowAddrSet::union_all(&[set1.clone(), set2.clone(), set3.clone()]);
616
617 let mut via_bitor = set1;
618 via_bitor |= &set2;
619 via_bitor |= &set3;
620
621 assert_eq!(via_union_all.true_rows(), via_bitor.true_rows());
622 assert_eq!(via_union_all.null_rows(), via_bitor.null_rows());
623 }
624
625 #[test]
626 fn test_nullable_row_addr_set_with_nulls() {
627 let set = NullableRowAddrSet::new(rows(&[1, 2, 3]), RowAddrTreeMap::new());
628 let set_with_nulls = set.with_nulls(rows(&[2]));
629
630 assert!(set_with_nulls.selected(1) && set_with_nulls.selected(3));
631 assert!(!set_with_nulls.selected(2)); }
633
634 #[test]
635 fn test_nullable_row_addr_set_len_and_is_empty() {
636 let set = nullable_set(&[1, 2, 3, 4, 5], &[2, 4]);
637
638 assert_eq!(set.len(), Some(3)); assert!(!set.is_empty());
641
642 let empty_set = NullableRowAddrSet::empty();
643 assert!(empty_set.is_empty());
644 assert_eq!(empty_set.len(), Some(0));
645 }
646
647 #[test]
648 fn test_nullable_row_addr_set_selected() {
649 let set = nullable_set(&[1, 2, 3], &[2]);
650
651 assert!(set.selected(1) && set.selected(3));
653 assert!(!set.selected(2)); assert!(!set.selected(4)); }
656
657 #[test]
658 fn test_nullable_row_addr_set_partial_eq() {
659 let set1 = nullable_set(&[1, 2, 3], &[2]);
660 let set2 = nullable_set(&[1, 2, 3], &[2]);
661 let set3 = nullable_set(&[1, 3], &[3]);
663
664 assert_eq!(set1, set2);
665 assert_ne!(set1, set3); }
667
668 #[test]
669 fn test_nullable_row_addr_set_bitand_fast_path() {
670 let set1 = nullable_set(&[1, 2, 3], &[]);
672 let set2 = nullable_set(&[2, 3, 4], &[]);
673
674 let mut result = set1;
675 result &= &set2;
676
677 assert!(result.selected(2) && result.selected(3));
679 assert!(!result.selected(1) && !result.selected(4));
680 assert!(result.null_rows().is_empty());
681 }
682
683 #[test]
684 fn test_nullable_row_addr_set_bitor_fast_path() {
685 let set1 = nullable_set(&[1, 2], &[]);
687 let set2 = nullable_set(&[3, 4], &[]);
688
689 let mut result = set1;
690 result |= &set2;
691
692 for id in [1, 2, 3, 4] {
694 assert!(result.selected(id));
695 }
696 assert!(result.null_rows().is_empty());
697 }
698
699 #[test]
700 fn test_nullable_row_id_mask_drop_nulls() {
701 let allow_mask = allow(&[1, 2, 3, 4], &[2, 4]);
703 let dropped = allow_mask.drop_nulls();
704 assert!(dropped.selected(1) && dropped.selected(3));
706 assert!(!dropped.selected(2) && !dropped.selected(4));
707
708 let block_mask = block(&[1, 2], &[3]);
710 let dropped = block_mask.drop_nulls();
711 assert!(!dropped.selected(1) && !dropped.selected(2) && !dropped.selected(3));
713 assert!(dropped.selected(4) && dropped.selected(5));
714 }
715
716 #[test]
717 fn test_nullable_row_id_mask_not_blocklist() {
718 let block_mask = block(&[1, 2], &[2]);
719 let not_mask = !block_mask;
720
721 assert!(matches!(not_mask, NullableRowAddrMask::AllowList(_)));
723 }
724
725 #[test]
726 fn test_nullable_row_id_mask_bitand_allow_allow_fast_path() {
727 let mask1 = allow(&[1, 2, 3], &[]);
729 let mask2 = allow(&[2, 3, 4], &[]);
730
731 let result = mask1 & mask2;
732 assert_mask_selects(&result, &[2, 3], &[1, 4]);
733 }
734
735 #[test]
736 fn test_nullable_row_id_mask_bitand_allow_block() {
737 let allow_mask = allow(&[1, 2, 3, 4, 5], &[2]);
738 let block_mask = block(&[3, 4], &[4]);
739
740 let result = allow_mask & block_mask;
741 assert_mask_selects(&result, &[1, 5], &[2, 3, 4]);
745 }
746
747 #[test]
748 fn test_nullable_row_id_mask_bitand_allow_block_fast_path() {
749 let allow_mask = allow(&[1, 2, 3], &[]);
751 let block_mask = block(&[2], &[]);
752
753 let result = allow_mask & block_mask;
754 assert_mask_selects(&result, &[1, 3], &[2]);
755 }
756
757 #[test]
758 fn test_nullable_row_id_mask_bitand_block_block() {
759 let block1 = block(&[1, 2], &[2]);
760 let block2 = block(&[2, 3], &[3]);
761
762 let result = block1 & block2;
763 assert_mask_selects(&result, &[4], &[1, 2, 3]);
766 }
767
768 #[test]
769 fn test_nullable_row_id_mask_bitand_block_block_fast_path() {
770 let block1 = block(&[1], &[]);
772 let block2 = block(&[2], &[]);
773
774 let result = block1 & block2;
775 assert_mask_selects(&result, &[3], &[1, 2]);
776 }
777
778 #[test]
779 fn test_nullable_row_id_mask_bitor_allow_allow_fast_path() {
780 let mask1 = allow(&[1, 2], &[]);
782 let mask2 = allow(&[3, 4], &[]);
783
784 let result = mask1 | mask2;
785 assert_mask_selects(&result, &[1, 2, 3, 4], &[5]);
786 }
787
788 #[test]
789 fn test_nullable_row_id_mask_bitor_allow_block() {
790 let allow_mask = allow(&[1, 2, 3], &[2]);
791 let block_mask = block(&[1, 4], &[4]);
792
793 let result = allow_mask | block_mask;
794 assert_mask_selects(&result, &[1, 2, 3], &[]);
797 }
798
799 #[test]
800 fn test_nullable_row_id_mask_bitor_allow_block_fast_path() {
801 let allow_mask = allow(&[1], &[]);
803 let block_mask = block(&[2], &[]);
804
805 let result = allow_mask | block_mask;
806 assert_mask_selects(&result, &[1, 3], &[2]);
808 }
809
810 #[test]
811 fn test_nullable_row_id_mask_bitor_block_block_fast_path() {
812 let block1 = block(&[1, 2], &[]);
814 let block2 = block(&[2, 3], &[]);
815
816 let result = block1 | block2;
817 assert_mask_selects(&result, &[1, 3, 4], &[2]);
819 }
820}