vortex_mask/
bitops.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::ops::{BitAnd, Not};
5
6use vortex_error::vortex_panic;
7
8use crate::{AllOr, Mask};
9
10impl BitAnd for &Mask {
11    type Output = Mask;
12
13    fn bitand(self, rhs: Self) -> Self::Output {
14        if self.len() != rhs.len() {
15            vortex_panic!("Masks must have the same length");
16        }
17
18        match (self.boolean_buffer(), rhs.boolean_buffer()) {
19            (AllOr::All, _) => rhs.clone(),
20            (_, AllOr::All) => self.clone(),
21            (AllOr::None, _) => Mask::new_false(self.len()),
22            (_, AllOr::None) => Mask::new_false(self.len()),
23            (AllOr::Some(lhs), AllOr::Some(rhs)) => Mask::from_buffer(lhs & rhs),
24        }
25    }
26}
27
28impl Not for &Mask {
29    type Output = Mask;
30
31    fn not(self) -> Self::Output {
32        match self.boolean_buffer() {
33            AllOr::All => Mask::new_false(self.len()),
34            AllOr::None => Mask::new_true(self.len()),
35            AllOr::Some(buffer) => Mask::from_buffer(!buffer),
36        }
37    }
38}
39
40#[cfg(test)]
41#[allow(clippy::many_single_char_names)]
42mod tests {
43    use arrow_buffer::BooleanBuffer;
44
45    use super::*;
46
47    #[test]
48    fn test_bitand_all_combinations() {
49        let len = 5;
50
51        // Test AllTrue & AllTrue
52        let all_true = Mask::new_true(len);
53        let result = &all_true & &all_true;
54        assert!(result.all_true());
55        assert_eq!(result.true_count(), len);
56
57        // Test AllTrue & AllFalse
58        let all_false = Mask::new_false(len);
59        let result = &all_true & &all_false;
60        assert!(result.all_false());
61        assert_eq!(result.true_count(), 0);
62
63        // Test AllFalse & AllTrue
64        let result = &all_false & &all_true;
65        assert!(result.all_false());
66        assert_eq!(result.true_count(), 0);
67
68        // Test AllFalse & AllFalse
69        let result = &all_false & &all_false;
70        assert!(result.all_false());
71        assert_eq!(result.true_count(), 0);
72    }
73
74    #[test]
75    fn test_bitand_with_values() {
76        let mask1 = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
77        let mask2 = Mask::from_buffer(BooleanBuffer::from_iter([true, true, false, false, true]));
78
79        let result = &mask1 & &mask2;
80        assert_eq!(result.len(), 5);
81        assert_eq!(result.true_count(), 2);
82        assert!(result.value(0)); // true & true = true
83        assert!(!result.value(1)); // false & true = false
84        assert!(!result.value(2)); // true & false = false
85        assert!(!result.value(3)); // false & false = false
86        assert!(result.value(4)); // true & true = true
87    }
88
89    #[test]
90    fn test_bitand_all_true_with_values() {
91        let all_true = Mask::new_true(5);
92        let values = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
93
94        // AllTrue & Values should return Values
95        let result = &all_true & &values;
96        assert_eq!(result.true_count(), 3);
97        assert_eq!(result.len(), 5);
98        assert!(result.value(0));
99        assert!(!result.value(1));
100        assert!(result.value(2));
101        assert!(!result.value(3));
102        assert!(result.value(4));
103    }
104
105    #[test]
106    fn test_bitand_all_false_with_values() {
107        let all_false = Mask::new_false(5);
108        let values = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
109
110        // AllFalse & Values should return AllFalse
111        let result = &all_false & &values;
112        assert!(result.all_false());
113        assert_eq!(result.true_count(), 0);
114    }
115
116    #[test]
117    fn test_bitand_values_with_all_true() {
118        let values = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
119        let all_true = Mask::new_true(5);
120
121        // Values & AllTrue should return Values
122        let result = &values & &all_true;
123        assert_eq!(result.true_count(), 3);
124        assert_eq!(result.len(), 5);
125        assert!(result.value(0));
126        assert!(!result.value(1));
127        assert!(result.value(2));
128        assert!(!result.value(3));
129        assert!(result.value(4));
130    }
131
132    #[test]
133    fn test_bitand_values_with_all_false() {
134        let values = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
135        let all_false = Mask::new_false(5);
136
137        // Values & AllFalse should return AllFalse
138        let result = &values & &all_false;
139        assert!(result.all_false());
140        assert_eq!(result.true_count(), 0);
141    }
142
143    #[test]
144    fn test_bitand_empty_masks() {
145        let empty1 = Mask::new_true(0);
146        let empty2 = Mask::new_false(0);
147
148        let result = &empty1 & &empty2;
149        assert_eq!(result.len(), 0);
150        assert!(result.is_empty());
151    }
152
153    #[test]
154    #[should_panic(expected = "Masks must have the same length")]
155    fn test_bitand_different_lengths() {
156        let mask1 = Mask::new_true(5);
157        let mask2 = Mask::new_true(3);
158        let _ = &mask1 & &mask2;
159    }
160
161    #[test]
162    fn test_not_all_true() {
163        let all_true = Mask::new_true(5);
164        let result = !&all_true;
165        assert!(result.all_false());
166        assert_eq!(result.true_count(), 0);
167        assert_eq!(result.len(), 5);
168    }
169
170    #[test]
171    fn test_not_all_false() {
172        let all_false = Mask::new_false(5);
173        let result = !&all_false;
174        assert!(result.all_true());
175        assert_eq!(result.true_count(), 5);
176        assert_eq!(result.len(), 5);
177    }
178
179    #[test]
180    fn test_not_values() {
181        let values = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
182        let result = !&values;
183
184        assert_eq!(result.len(), 5);
185        assert_eq!(result.true_count(), 2);
186        assert!(!result.value(0)); // !true = false
187        assert!(result.value(1)); // !false = true
188        assert!(!result.value(2)); // !true = false
189        assert!(result.value(3)); // !false = true
190        assert!(!result.value(4)); // !true = false
191    }
192
193    #[test]
194    fn test_not_empty() {
195        let empty_true = Mask::new_true(0);
196        let result = !&empty_true;
197        assert_eq!(result.len(), 0);
198        assert!(result.is_empty());
199
200        let empty_false = Mask::new_false(0);
201        let result = !&empty_false;
202        assert_eq!(result.len(), 0);
203        assert!(result.is_empty());
204    }
205
206    #[test]
207    fn test_double_not() {
208        let original =
209            Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
210        let double_not = !&(!&original);
211
212        // Double negation should return the original
213        assert_eq!(double_not.true_count(), original.true_count());
214        for i in 0..5 {
215            assert_eq!(double_not.value(i), original.value(i));
216        }
217    }
218
219    #[test]
220    fn test_demorgan_law() {
221        // Test De Morgan's law: !(A & B) = !A | !B
222        // Since we only have AND and NOT, we can't test the full law,
223        // but we can verify that !(A & B) behaves correctly
224        let a = Mask::from_buffer(BooleanBuffer::from_iter([true, true, false, false]));
225        let b = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false]));
226
227        let and_result = &a & &b;
228        let not_and = !&and_result;
229
230        assert_eq!(not_and.len(), 4);
231        assert!(!not_and.value(0)); // !(true & true) = false
232        assert!(not_and.value(1)); // !(true & false) = true
233        assert!(not_and.value(2)); // !(false & true) = true
234        assert!(not_and.value(3)); // !(false & false) = true
235    }
236
237    #[test]
238    fn test_bitand_associativity() {
239        // Test (A & B) & C = A & (B & C)
240        let a = Mask::from_buffer(BooleanBuffer::from_iter([true, true, false, true]));
241        let b = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, true]));
242        let c = Mask::from_buffer(BooleanBuffer::from_iter([false, true, true, true]));
243
244        let left_assoc = &(&a & &b) & &c;
245        let right_assoc = &a & &(&b & &c);
246
247        assert_eq!(left_assoc.true_count(), right_assoc.true_count());
248        for i in 0..4 {
249            assert_eq!(left_assoc.value(i), right_assoc.value(i));
250        }
251    }
252
253    #[test]
254    fn test_bitand_commutativity() {
255        // Test A & B = B & A
256        let a = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false]));
257        let b = Mask::from_buffer(BooleanBuffer::from_iter([false, true, false, true]));
258
259        let ab = &a & &b;
260        let ba = &b & &a;
261
262        assert_eq!(ab.true_count(), ba.true_count());
263        for i in 0..4 {
264            assert_eq!(ab.value(i), ba.value(i));
265        }
266    }
267
268    #[test]
269    fn test_bitand_identity() {
270        // Test A & AllTrue = A
271        let mask = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false]));
272        let all_true = Mask::new_true(4);
273
274        let result = &mask & &all_true;
275        assert_eq!(result.true_count(), mask.true_count());
276        for i in 0..4 {
277            assert_eq!(result.value(i), mask.value(i));
278        }
279    }
280
281    #[test]
282    fn test_bitand_annihilator() {
283        // Test A & AllFalse = AllFalse
284        let mask = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false]));
285        let all_false = Mask::new_false(4);
286
287        let result = &mask & &all_false;
288        assert!(result.all_false());
289        assert_eq!(result.true_count(), 0);
290    }
291
292    #[test]
293    fn test_bitand_idempotence() {
294        // Test A & A = A
295        let mask = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false, true]));
296        let result = &mask & &mask;
297
298        assert_eq!(result.true_count(), mask.true_count());
299        for i in 0..5 {
300            assert_eq!(result.value(i), mask.value(i));
301        }
302    }
303
304    #[test]
305    fn test_complex_expression() {
306        // Test a more complex expression: !((!A) & B)
307        let a = Mask::from_buffer(BooleanBuffer::from_iter([true, false, true, false]));
308        let b = Mask::from_buffer(BooleanBuffer::from_iter([true, true, false, false]));
309
310        let not_a = !&a;
311        let not_a_and_b = &not_a & &b;
312        let result = !&not_a_and_b;
313
314        // Verify the result manually
315        assert!(result.value(0)); // !((!true) & true) = !(false & true) = !false = true
316        assert!(!result.value(1)); // !((!false) & true) = !(true & true) = !true = false
317        assert!(result.value(2)); // !((!true) & false) = !(false & false) = !false = true
318        assert!(result.value(3)); // !((!false) & false) = !(true & false) = !false = true
319    }
320}