vortex_mask/
eq.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use crate::Mask;
5
6impl PartialEq for Mask {
7    #[inline]
8    fn eq(&self, other: &Self) -> bool {
9        if self.len() != other.len() {
10            return false;
11        }
12        if self.true_count() != other.true_count() {
13            return false;
14        }
15
16        // TODO(ngates): we could compare by indices if density is low enough
17        self.boolean_buffer() == other.boolean_buffer()
18    }
19}
20
21impl Eq for Mask {}
22
23#[cfg(test)]
24mod test {
25    use arrow_buffer::BooleanBuffer;
26
27    use crate::Mask;
28
29    #[test]
30    fn filter_mask_eq() {
31        assert_eq!(
32            Mask::new_true(5),
33            Mask::from_buffer(BooleanBuffer::new_set(5))
34        );
35        assert_eq!(
36            Mask::new_false(5),
37            Mask::from_buffer(BooleanBuffer::new_unset(5))
38        );
39        assert_eq!(
40            Mask::from_indices(5, vec![0, 2, 3]),
41            Mask::from_slices(5, vec![(0, 1), (2, 4)])
42        );
43        assert_eq!(
44            Mask::from_indices(5, vec![0, 2, 3]),
45            Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, true, false]))
46        );
47    }
48
49    #[test]
50    fn test_mask_eq_different_lengths() {
51        let mask1 = Mask::new_true(5);
52        let mask2 = Mask::new_true(3);
53        assert_ne!(mask1, mask2);
54    }
55
56    #[test]
57    fn test_mask_eq_different_true_counts() {
58        let mask1 = Mask::from_buffer(BooleanBuffer::from_iter([true, true, false]));
59        let mask2 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, false]));
60        assert_ne!(mask1, mask2);
61    }
62
63    #[test]
64    fn test_mask_eq_same_count_different_positions() {
65        let mask1 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, false]));
66        let mask2 = Mask::from_buffer(BooleanBuffer::from_iter([false, true, false]));
67        assert_ne!(mask1, mask2);
68    }
69
70    #[test]
71    fn test_mask_eq_all_variants() {
72        // Test AllTrue == AllTrue
73        let all_true1 = Mask::new_true(5);
74        let all_true2 = Mask::new_true(5);
75        assert_eq!(all_true1, all_true2);
76
77        // Test AllFalse == AllFalse
78        let all_false1 = Mask::new_false(5);
79        let all_false2 = Mask::new_false(5);
80        assert_eq!(all_false1, all_false2);
81
82        // Test AllTrue != AllFalse
83        assert_ne!(all_true1, all_false1);
84
85        // Test Values == Values
86        let values1 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true]));
87        let values2 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true]));
88        assert_eq!(values1, values2);
89
90        // Test AllTrue != Values (even if all values are true)
91        let all_true_values = Mask::from_buffer(BooleanBuffer::new_set(5));
92        assert_eq!(all_true1, all_true_values); // They should be equal
93
94        // Test AllFalse != Values (even if all values are false)
95        let all_false_values = Mask::from_buffer(BooleanBuffer::new_unset(5));
96        assert_eq!(all_false1, all_false_values); // They should be equal
97    }
98
99    #[test]
100    fn test_mask_eq_reflexive() {
101        // Test that a mask equals itself
102        let mask = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
103        assert_eq!(mask, mask);
104    }
105
106    #[test]
107    fn test_mask_eq_symmetric() {
108        // Test that if a == b then b == a
109        let mask1 = Mask::from_indices(5, vec![0, 2, 4]);
110        let mask2 = Mask::from_slices(5, vec![(0, 1), (2, 3), (4, 5)]);
111        assert_eq!(mask1, mask2);
112        assert_eq!(mask2, mask1);
113    }
114
115    #[test]
116    fn test_mask_eq_transitive() {
117        // Test that if a == b and b == c then a == c
118        let mask1 = Mask::from_indices(5, vec![1, 3]);
119        let mask2 = Mask::from_slices(5, vec![(1, 2), (3, 4)]);
120        let mask3 = Mask::from_buffer(BooleanBuffer::from_iter([false, true, false, true, false]));
121
122        assert_eq!(mask1, mask2);
123        assert_eq!(mask2, mask3);
124        assert_eq!(mask1, mask3);
125    }
126
127    #[test]
128    fn test_mask_eq_empty() {
129        // All empty masks become AllFalse regardless of input type
130        let empty1 = Mask::new_true(0);
131        let empty2 = Mask::new_false(0);
132        let empty3 = Mask::from_buffer(BooleanBuffer::new_set(0));
133        let empty4 = Mask::from_buffer(BooleanBuffer::new_unset(0));
134
135        // All should be AllFalse(0) when created from buffer
136        assert!(matches!(empty3, Mask::AllFalse(0)));
137        assert!(matches!(empty4, Mask::AllFalse(0)));
138
139        // new_true(0) is AllTrue(0), new_false(0) is AllFalse(0)
140        assert!(matches!(empty1, Mask::AllTrue(0)));
141        assert!(matches!(empty2, Mask::AllFalse(0)));
142    }
143
144    #[test]
145    fn test_mask_eq_different_representations() {
146        // Test that masks with the same logical values but different internal representations are equal
147        let indices = vec![0, 1, 2, 5, 6, 9];
148        let slices = vec![(0, 3), (5, 7), (9, 10)];
149        let buffer = BooleanBuffer::from_iter([
150            true, true, true, false, false, true, true, false, false, true,
151        ]);
152
153        let mask1 = Mask::from_indices(10, indices);
154        let mask2 = Mask::from_slices(10, slices);
155        let mask3 = Mask::from_buffer(buffer);
156
157        assert_eq!(mask1, mask2);
158        assert_eq!(mask2, mask3);
159        assert_eq!(mask1, mask3);
160    }
161}