1#[cfg(test)]
8use super::container::Container;
9use super::Bitmap;
10#[cfg(not(feature = "std"))]
11use alloc::collections::BTreeMap;
12use core::cmp::Ordering;
13#[cfg(feature = "std")]
14use std::collections::BTreeMap;
15
16impl Bitmap {
17 pub fn union(&self, other: &Self, limit: u64) -> Self {
21 let mut result = BTreeMap::new();
22 let mut remaining = limit;
23
24 let mut a_iter = self.containers.iter().peekable();
25 let mut b_iter = other.containers.iter().peekable();
26
27 while remaining > 0 {
28 let a_key = a_iter.peek().map(|(&key, _)| key);
29 let b_key = b_iter.peek().map(|(&key, _)| key);
30 let Some(key) = next_key(a_key, b_key) else {
31 break;
32 };
33
34 let (container, count) = match (a_key == Some(key), b_key == Some(key)) {
35 (true, true) => {
36 let (_, a_container) = a_iter.next().unwrap();
37 let (_, b_container) = b_iter.next().unwrap();
38 a_container.union(b_container, remaining)
39 }
40 (true, false) => {
41 let (_, container) = a_iter.next().unwrap();
42 container.limit(remaining)
43 }
44 (false, true) => {
45 let (_, container) = b_iter.next().unwrap();
46 container.limit(remaining)
47 }
48 (false, false) => unreachable!("next_key returned a key from neither iterator"),
49 };
50
51 if count > 0 {
52 result.insert(key, container);
53 remaining -= count;
54 }
55 }
56
57 Self { containers: result }
58 }
59
60 pub fn intersection(&self, other: &Self, limit: u64) -> Self {
64 let mut result = BTreeMap::new();
65 let mut remaining = limit;
66
67 let (smaller, larger) = if self.containers.len() <= other.containers.len() {
68 (&self.containers, &other.containers)
69 } else {
70 (&other.containers, &self.containers)
71 };
72
73 for (&key, container) in smaller.iter() {
74 if remaining == 0 {
75 break;
76 }
77
78 if let Some(other_container) = larger.get(&key) {
79 let (container, count) = container.intersection(other_container, remaining);
80 if count > 0 {
81 result.insert(key, container);
82 remaining -= count;
83 }
84 }
85 }
86
87 Self { containers: result }
88 }
89
90 pub fn difference(&self, other: &Self, limit: u64) -> Self {
94 let mut result = BTreeMap::new();
95 let mut remaining = limit;
96
97 for (&key, container) in self.containers.iter() {
98 if remaining == 0 {
99 break;
100 }
101
102 let (container, count) = other.containers.get(&key).map_or_else(
103 || container.limit(remaining),
104 |other_container| container.difference(other_container, remaining),
105 );
106
107 if count > 0 {
108 result.insert(key, container);
109 remaining -= count;
110 }
111 }
112
113 Self { containers: result }
114 }
115
116 pub fn is_subset(&self, other: &Self) -> bool {
118 if self.len() > other.len() {
119 return false;
120 }
121
122 self.containers.iter().all(|(key, container)| {
123 other
124 .containers
125 .get(key)
126 .is_some_and(|other_container| container.is_subset(other_container))
127 })
128 }
129
130 pub fn intersects(&self, other: &Self) -> bool {
132 let (smaller, larger) = if self.containers.len() <= other.containers.len() {
133 (&self.containers, &other.containers)
134 } else {
135 (&other.containers, &self.containers)
136 };
137
138 smaller.iter().any(|(key, container)| {
139 larger
140 .get(key)
141 .is_some_and(|other_container| container.intersects(other_container))
142 })
143 }
144}
145
146fn next_key(a: Option<u64>, b: Option<u64>) -> Option<u64> {
147 match a.cmp(&b) {
148 Ordering::Equal => a,
149 Ordering::Less => a.or(b),
150 Ordering::Greater => b.or(a),
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use crate::bitmap::BitMap as Reference;
158
159 fn reference_len(a: &Bitmap, b: &Bitmap) -> u64 {
160 a.iter().chain(b.iter()).max().map_or(0, |value| value + 1)
161 }
162
163 fn build_reference(bitmap: &Bitmap, len: u64) -> Reference {
164 let mut reference = Reference::zeroes(len);
165 for value in bitmap.iter() {
166 reference.set(value, true);
167 }
168 reference
169 }
170
171 fn expected_values(reference: &Reference, limit: u64) -> Vec<u64> {
172 if limit == 0 {
173 return Vec::new();
174 }
175
176 let mut values = Vec::new();
177 for value in 0..reference.len() {
178 if reference.get(value) {
179 values.push(value);
180 if values.len() as u64 == limit {
181 break;
182 }
183 }
184 }
185 values
186 }
187
188 fn assert_matches_reference(result: &Bitmap, reference: &Reference, limit: u64, op: &str) {
189 let actual: Vec<_> = result.iter().collect();
190 let expected = expected_values(reference, limit);
191 assert_eq!(actual, expected, "{op} mismatch");
192 assert_eq!(result.len(), expected.len() as u64, "{op} length mismatch");
193 }
194
195 fn assert_union_matches_reference(a: &Bitmap, b: &Bitmap, limit: u64) -> Bitmap {
196 let len = reference_len(a, b);
197 let mut reference = build_reference(a, len);
198 reference.or(&build_reference(b, len));
199
200 let result = a.union(b, limit);
201 assert_matches_reference(&result, &reference, limit, "union");
202 result
203 }
204
205 fn assert_intersection_matches_reference(a: &Bitmap, b: &Bitmap, limit: u64) -> Bitmap {
206 let len = reference_len(a, b);
207 let mut reference = build_reference(a, len);
208 reference.and(&build_reference(b, len));
209
210 let result = a.intersection(b, limit);
211 assert_matches_reference(&result, &reference, limit, "intersection");
212 result
213 }
214
215 fn assert_difference_matches_reference(a: &Bitmap, b: &Bitmap, limit: u64) -> Bitmap {
216 let len = reference_len(a, b);
217 let mut reference = build_reference(a, len);
218 for value in b.iter() {
219 reference.set(value, false);
220 }
221
222 let result = a.difference(b, limit);
223 assert_matches_reference(&result, &reference, limit, "difference");
224 result
225 }
226
227 fn assert_is_subset_matches_reference(a: &Bitmap, b: &Bitmap) -> bool {
228 let len = reference_len(a, b);
229 let a_reference = build_reference(a, len);
230 let b_reference = build_reference(b, len);
231 let expected = (0..len).all(|value| !a_reference.get(value) || b_reference.get(value));
232 let result = a.is_subset(b);
233 assert_eq!(result, expected, "is_subset mismatch");
234 result
235 }
236
237 fn assert_intersects_matches_reference(a: &Bitmap, b: &Bitmap) -> bool {
238 let len = reference_len(a, b);
239 let a_reference = build_reference(a, len);
240 let b_reference = build_reference(b, len);
241 let expected = (0..len).any(|value| a_reference.get(value) && b_reference.get(value));
242 let result = a.intersects(b);
243 assert_eq!(result, expected, "intersects mismatch");
244 result
245 }
246
247 #[test]
248 fn test_union_basic() {
249 let a = Bitmap::from_iter([1, 2, 3]);
250 let b = Bitmap::from_iter([2, 3, 4, 5]);
251
252 assert_union_matches_reference(&a, &b, u64::MAX);
253 }
254
255 #[test]
256 fn test_union_with_limit() {
257 let a = Bitmap::from_iter([1, 2, 3]);
258 let b = Bitmap::from_iter([4, 5, 6]);
259
260 assert_union_matches_reference(&a, &b, 4);
261 }
262
263 #[test]
264 fn test_union_empty() {
265 let a = Bitmap::new();
266 let b = Bitmap::from_iter([1, 2, 3]);
267
268 assert_union_matches_reference(&a, &b, u64::MAX);
269 }
270
271 #[test]
272 fn test_union_a_key_less_than_b() {
273 let a = Bitmap::from_iter([1, 2, 3]);
277 let b = Bitmap::from_iter([65_536, 65_537, 65_538]);
278 assert_union_matches_reference(&a, &b, u64::MAX);
279 }
280
281 #[test]
282 fn test_union_b_key_less_than_a() {
283 let a = Bitmap::from_iter([65_536, 65_537, 65_538]);
285 let b = Bitmap::from_iter([1, 2, 3]);
286 assert_union_matches_reference(&a, &b, u64::MAX);
287 }
288
289 #[test]
290 fn test_union_alternating_keys() {
291 let mut a = Bitmap::new();
294 a.insert(10); a.insert(2 * 65_536 + 10); let mut b = Bitmap::new();
298 b.insert(65_536 + 20); b.insert(3 * 65_536 + 20); let result = assert_union_matches_reference(&a, &b, u64::MAX);
302 assert_eq!(result.container_count(), 4);
303 }
304
305 #[test]
306 fn test_union_disjoint_keys_with_limit() {
307 let a = Bitmap::from_iter([1, 2, 3]);
310 let b = Bitmap::from_iter([65_536, 65_537, 65_538]);
311 assert_union_matches_reference(&a, &b, 2);
312 }
313
314 #[test]
315 fn test_container_union_array_array_promotes_to_bitmap_when_oversized() {
316 use commonware_codec::{Decode, Encode};
317
318 let mut a = Bitmap::new();
319 let mut b = Bitmap::new();
320 for i in 0..4000u64 {
324 a.insert(i * 4);
325 b.insert(i * 4 + 1);
326 }
327 assert!(matches!(
328 a.containers().get(&0).unwrap(),
329 Container::Array(_)
330 ));
331 assert!(matches!(
332 b.containers().get(&0).unwrap(),
333 Container::Array(_)
334 ));
335
336 let result = assert_union_matches_reference(&a, &b, u64::MAX);
337
338 assert!(
340 matches!(result.containers().get(&0).unwrap(), Container::Bitmap(_)),
341 "oversized array union must promote to Bitmap variant"
342 );
343
344 let bytes = result.encode();
346 let decoded = Bitmap::decode_cfg(bytes, &(..=10usize).into()).unwrap();
347 assert_eq!(result, decoded);
348 }
349
350 #[test]
351 fn test_container_union_bitmap_bitmap_fast_path() {
352 let mut a = Bitmap::new();
357 let mut b = Bitmap::new();
358 for i in 0..4097u64 {
359 a.insert(i * 2); b.insert(i * 2 + 1); }
362 assert!(matches!(
363 a.containers().get(&0).unwrap(),
364 Container::Bitmap(_)
365 ));
366 assert!(matches!(
367 b.containers().get(&0).unwrap(),
368 Container::Bitmap(_)
369 ));
370
371 assert_union_matches_reference(&a, &b, u64::MAX);
372 }
373
374 #[test]
375 fn test_container_union_bitmap_bitmap_limit_truncates() {
376 let mut a = Bitmap::new();
379 let mut b = Bitmap::new();
380 for i in 0..4097u64 {
381 a.insert(i * 2);
382 b.insert(i * 2 + 1);
383 }
384
385 assert_union_matches_reference(&a, &b, 100);
386 }
387
388 #[test]
389 fn test_container_union_mixed_variants_general_path() {
390 let mut a = Bitmap::new();
394 a.insert(1);
395 a.insert(50);
396 a.insert(100);
397
398 let mut b = Bitmap::new();
399 for i in 0..4097u64 {
400 b.insert(i * 2 + 200); }
402 assert!(matches!(
403 a.containers().get(&0).unwrap(),
404 Container::Array(_)
405 ));
406 assert!(matches!(
407 b.containers().get(&0).unwrap(),
408 Container::Bitmap(_)
409 ));
410
411 assert_union_matches_reference(&a, &b, u64::MAX);
412 }
413
414 #[test]
415 fn test_intersection_basic() {
416 let a = Bitmap::from_iter([1, 2, 3, 4]);
417 let b = Bitmap::from_iter([2, 3, 4, 5]);
418
419 assert_intersection_matches_reference(&a, &b, u64::MAX);
420 }
421
422 #[test]
423 fn test_intersection_with_limit() {
424 let a = Bitmap::from_iter([1, 2, 3, 4, 5]);
425 let b = Bitmap::from_iter([1, 2, 3, 4, 5]);
426
427 assert_intersection_matches_reference(&a, &b, 3);
428 }
429
430 #[test]
431 fn test_intersection_disjoint() {
432 let a = Bitmap::from_iter([1, 2, 3]);
433 let b = Bitmap::from_iter([4, 5, 6]);
434
435 assert_intersection_matches_reference(&a, &b, u64::MAX);
436 }
437
438 #[test]
439 fn test_intersection_containers_bitmap_bitmap_fast_path() {
440 let mut a = Bitmap::new();
443 let mut b = Bitmap::new();
444 for i in 0..4097u64 {
448 a.insert(i * 2);
449 b.insert(i * 4);
450 }
451 assert!(matches!(
452 a.containers().get(&0).unwrap(),
453 Container::Bitmap(_)
454 ));
455 assert!(matches!(
456 b.containers().get(&0).unwrap(),
457 Container::Bitmap(_)
458 ));
459
460 assert_intersection_matches_reference(&a, &b, u64::MAX);
461 }
462
463 #[test]
464 fn test_intersection_containers_bitmap_bitmap_limit_truncates() {
465 let mut a = Bitmap::new();
468 let mut b = Bitmap::new();
469 for i in 0..4097u64 {
470 a.insert(i * 2);
471 b.insert(i * 4);
472 }
473
474 assert_intersection_matches_reference(&a, &b, 50);
475 }
476
477 #[test]
478 fn test_intersection_containers_mixed_variants_general_path() {
479 let mut a = Bitmap::new();
483 a.insert(1);
484 a.insert(50);
485 a.insert(200); let mut b = Bitmap::new();
488 for i in 0..4097u64 {
489 b.insert(i * 2 + 200);
490 }
491 assert!(matches!(
492 a.containers().get(&0).unwrap(),
493 Container::Array(_)
494 ));
495 assert!(matches!(
496 b.containers().get(&0).unwrap(),
497 Container::Bitmap(_)
498 ));
499
500 assert_intersection_matches_reference(&a, &b, u64::MAX);
501 }
502
503 #[test]
504 fn test_difference_basic() {
505 let a = Bitmap::from_iter([1, 2, 3, 4]);
506 let b = Bitmap::from_iter([2, 3]);
507
508 assert_difference_matches_reference(&a, &b, u64::MAX);
509 }
510
511 #[test]
512 fn test_difference_with_limit() {
513 let a = Bitmap::from_iter([1, 2, 3, 4, 5]);
514 let b = Bitmap::from_iter([2, 4]);
515
516 assert_difference_matches_reference(&a, &b, 2);
517 }
518
519 #[test]
520 fn test_difference_all_removed() {
521 let a = Bitmap::from_iter([1, 2, 3]);
522 let b = Bitmap::from_iter([1, 2, 3, 4, 5]);
523
524 assert_difference_matches_reference(&a, &b, u64::MAX);
525 }
526
527 #[test]
528 fn test_container_difference_bitmap_bitmap_fast_path() {
529 let mut a = Bitmap::new();
532 let mut b = Bitmap::new();
533 for i in 0..4097u64 {
537 a.insert(i * 2);
538 b.insert(i * 4);
539 }
540 assert!(matches!(
541 a.containers().get(&0).unwrap(),
542 Container::Bitmap(_)
543 ));
544 assert!(matches!(
545 b.containers().get(&0).unwrap(),
546 Container::Bitmap(_)
547 ));
548
549 assert_difference_matches_reference(&a, &b, u64::MAX);
550 }
551
552 #[test]
553 fn test_container_difference_bitmap_bitmap_limit_truncates() {
554 let mut a = Bitmap::new();
557 let mut b = Bitmap::new();
558 for i in 0..4097u64 {
559 a.insert(i * 2);
560 b.insert(i * 4);
561 }
562
563 assert_difference_matches_reference(&a, &b, 30);
564 }
565
566 #[test]
567 fn test_container_difference_mixed_variants_general_path() {
568 let mut a = Bitmap::new();
572 a.insert(1);
573 a.insert(50);
574 a.insert(200);
575
576 let mut b = Bitmap::new();
577 for i in 0..4097u64 {
578 b.insert(i * 2 + 200); }
580 assert!(matches!(
581 a.containers().get(&0).unwrap(),
582 Container::Array(_)
583 ));
584 assert!(matches!(
585 b.containers().get(&0).unwrap(),
586 Container::Bitmap(_)
587 ));
588
589 assert_difference_matches_reference(&a, &b, u64::MAX);
590 }
591
592 #[test]
593 fn test_union_multiple_containers() {
594 let mut a = Bitmap::new();
595 let mut b = Bitmap::new();
596
597 a.insert(100);
599 a.insert(65536 + 100); b.insert(200);
602 b.insert(65536 + 200); assert_union_matches_reference(&a, &b, u64::MAX);
605 }
606
607 #[test]
608 fn test_intersection_multiple_containers() {
609 let mut a = Bitmap::new();
610 let mut b = Bitmap::new();
611
612 a.insert(100);
613 a.insert(200);
614 a.insert(65536 + 100);
615
616 b.insert(200);
617 b.insert(300);
618 b.insert(65536 + 100);
619
620 assert_intersection_matches_reference(&a, &b, u64::MAX);
621 }
622
623 #[test]
624 fn test_operations_with_zero_limit() {
625 let a = Bitmap::from_iter([1, 2, 3]);
626 let b = Bitmap::from_iter([2, 3, 4]);
627
628 assert_union_matches_reference(&a, &b, 0);
629 assert_intersection_matches_reference(&a, &b, 0);
630 assert_difference_matches_reference(&a, &b, 0);
631 }
632
633 #[test]
636 fn test_is_subset_proper() {
637 let a = Bitmap::from_iter([1, 2, 3]);
638 let b = Bitmap::from_iter([1, 2, 3, 4, 5]);
639 assert!(assert_is_subset_matches_reference(&a, &b));
640 assert!(!assert_is_subset_matches_reference(&b, &a));
641 }
642
643 #[test]
644 fn test_is_subset_equal() {
645 let a = Bitmap::from_iter([1, 2, 3]);
646 let b = Bitmap::from_iter([1, 2, 3]);
647 assert!(assert_is_subset_matches_reference(&a, &b));
648 assert!(assert_is_subset_matches_reference(&b, &a));
649 }
650
651 #[test]
652 fn test_is_subset_empty() {
653 let empty = Bitmap::new();
654 let nonempty = Bitmap::from_iter([1, 2, 3]);
655 assert!(assert_is_subset_matches_reference(&empty, &nonempty));
657 assert!(assert_is_subset_matches_reference(&empty, &empty));
658 assert!(!assert_is_subset_matches_reference(&nonempty, &empty));
660 }
661
662 #[test]
663 fn test_is_subset_missing_value_same_container() {
664 let a = Bitmap::from_iter([1, 2, 3]);
665 let b = Bitmap::from_iter([1, 3]); assert!(!assert_is_subset_matches_reference(&a, &b));
667 }
668
669 #[test]
670 fn test_is_subset_missing_container() {
671 let a = Bitmap::from_iter([1, 65536 + 100]);
673 let b = Bitmap::from_iter([1, 2, 3]);
674 assert!(!assert_is_subset_matches_reference(&a, &b));
675 }
676
677 #[test]
678 fn test_is_subset_multi_container() {
679 let mut a = Bitmap::new();
680 let mut b = Bitmap::new();
681 a.insert(100);
682 a.insert(65536 + 50);
683 a.insert(131_072 + 7);
684
685 b.insert(50);
686 b.insert(100);
687 b.insert(65536 + 50);
688 b.insert(65536 + 100);
689 b.insert(131_072 + 7);
690 b.insert(131_072 + 8);
691
692 assert!(assert_is_subset_matches_reference(&a, &b));
693 assert!(!assert_is_subset_matches_reference(&b, &a));
694 }
695
696 #[test]
697 fn test_is_subset_cardinality_short_circuit() {
698 let a = Bitmap::from_iter([1, 2, 3, 4]);
700 let b = Bitmap::from_iter([1, 2]);
701 assert!(!assert_is_subset_matches_reference(&a, &b));
702 }
703
704 #[test]
707 fn test_intersects_overlap() {
708 let a = Bitmap::from_iter([1, 2, 3]);
709 let b = Bitmap::from_iter([3, 4, 5]);
710 assert!(assert_intersects_matches_reference(&a, &b));
711 assert!(assert_intersects_matches_reference(&b, &a));
712 }
713
714 #[test]
715 fn test_intersects_disjoint() {
716 let a = Bitmap::from_iter([1, 2, 3]);
717 let b = Bitmap::from_iter([4, 5, 6]);
718 assert!(!assert_intersects_matches_reference(&a, &b));
719 assert!(!assert_intersects_matches_reference(&b, &a));
720 }
721
722 #[test]
723 fn test_intersects_one_empty() {
724 let a = Bitmap::new();
725 let b = Bitmap::from_iter([1, 2, 3]);
726 assert!(!assert_intersects_matches_reference(&a, &b));
727 assert!(!assert_intersects_matches_reference(&b, &a));
728 }
729
730 #[test]
731 fn test_intersects_both_empty() {
732 let a = Bitmap::new();
733 let b = Bitmap::new();
734 assert!(!assert_intersects_matches_reference(&a, &b));
735 }
736
737 #[test]
738 fn test_intersects_self() {
739 let a = Bitmap::from_iter([1, 2, 3]);
740 assert!(assert_intersects_matches_reference(&a, &a));
741 }
742
743 #[test]
744 fn test_intersects_multi_container_only_in_second() {
745 let mut a = Bitmap::new();
747 let mut b = Bitmap::new();
748 a.insert(100);
749 a.insert(65536 + 50);
750 b.insert(200);
751 b.insert(65536 + 50); assert!(assert_intersects_matches_reference(&a, &b));
754 assert!(assert_intersects_matches_reference(&b, &a));
755 }
756
757 #[test]
758 fn test_intersects_multi_container_no_overlap() {
759 let mut a = Bitmap::new();
761 let mut b = Bitmap::new();
762 a.insert(100);
763 a.insert(65536 + 50);
764 b.insert(200);
765 b.insert(65536 + 99);
766
767 assert!(!assert_intersects_matches_reference(&a, &b));
768 assert!(!assert_intersects_matches_reference(&b, &a));
769 }
770
771 #[test]
772 fn test_intersects_disjoint_keys() {
773 let mut a = Bitmap::new();
775 let mut b = Bitmap::new();
776 a.insert(100);
777 b.insert(65536 + 50);
778 assert!(!assert_intersects_matches_reference(&a, &b));
779 }
780
781 #[test]
784 fn test_intersects_iff_intersection_nonempty() {
785 let cases = [
787 (vec![1, 2, 3], vec![3, 4, 5]),
788 (vec![1, 2, 3], vec![4, 5, 6]),
789 (vec![], vec![1, 2, 3]),
790 (vec![1, 65536 + 50], vec![100, 65536 + 50]),
791 (vec![1, 65536 + 50], vec![100, 65536 + 99]),
792 ];
793 for (a_vals, b_vals) in cases {
794 let a = Bitmap::from_iter(a_vals.iter().copied());
795 let b = Bitmap::from_iter(b_vals.iter().copied());
796 let inter = assert_intersection_matches_reference(&a, &b, u64::MAX);
797 assert_eq!(
798 assert_intersects_matches_reference(&a, &b),
799 !inter.is_empty(),
800 "mismatch for a={a_vals:?} b={b_vals:?}"
801 );
802 }
803 }
804
805 #[test]
806 fn test_is_subset_iff_difference_empty() {
807 let cases = [
809 (vec![1, 2], vec![1, 2, 3]),
810 (vec![1, 2, 3], vec![1, 2]),
811 (vec![], vec![1, 2, 3]),
812 (vec![1, 2, 3], vec![]),
813 (vec![1, 65536 + 50], vec![1, 65536 + 50, 131_072]),
814 ];
815 for (a_vals, b_vals) in cases {
816 let a = Bitmap::from_iter(a_vals.iter().copied());
817 let b = Bitmap::from_iter(b_vals.iter().copied());
818 let diff = assert_difference_matches_reference(&a, &b, u64::MAX);
819 assert_eq!(
820 assert_is_subset_matches_reference(&a, &b),
821 diff.is_empty(),
822 "mismatch for a={a_vals:?} b={b_vals:?}"
823 );
824 }
825 }
826}