vortex_mask/
eq.rs

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