1use std::{
2 mem,
3 ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Deref, Sub, SubAssign},
4};
5
6use crate::{CowSplinter, Cut, PartitionRead, Splinter, SplinterRef};
7
8impl<B: Deref<Target = [u8]>> PartialEq<SplinterRef<B>> for Splinter {
9 #[inline]
10 fn eq(&self, other: &SplinterRef<B>) -> bool {
11 self.inner() == &other.load_unchecked()
12 }
13}
14
15impl<B: Deref<Target = [u8]>> PartialEq<CowSplinter<B>> for Splinter {
16 fn eq(&self, other: &CowSplinter<B>) -> bool {
17 match other {
18 CowSplinter::Ref(splinter_ref) => self.eq(splinter_ref),
19 CowSplinter::Owned(splinter) => self.eq(splinter),
20 }
21 }
22}
23
24impl Cut for Splinter {
25 type Out = Self;
26
27 fn cut(&mut self, rhs: &Self) -> Self::Out {
28 Self::new(self.inner_mut().cut(rhs.inner()))
29 }
30}
31
32impl<B: Deref<Target = [u8]>> Cut<SplinterRef<B>> for Splinter {
33 type Out = Self;
34
35 fn cut(&mut self, rhs: &SplinterRef<B>) -> Self::Out {
36 Self::new(self.inner_mut().cut(&rhs.load_unchecked()))
37 }
38}
39
40impl<B: Deref<Target = [u8]>> Cut<CowSplinter<B>> for Splinter {
41 type Out = Self;
42
43 fn cut(&mut self, rhs: &CowSplinter<B>) -> Self::Out {
44 match rhs {
45 CowSplinter::Ref(splinter_ref) => self.cut(splinter_ref),
46 CowSplinter::Owned(splinter) => self.cut(splinter),
47 }
48 }
49}
50
51macro_rules! binary_bitop {
52 ($BitOp:tt, $bitop:ident, $bitassign:path) => {
53 impl $BitOp<Splinter> for Splinter {
54 type Output = Splinter;
55 #[inline]
56 fn $bitop(mut self, rhs: Splinter) -> Self::Output {
57 $bitassign(&mut self, rhs);
58 self
59 }
60 }
61 impl $BitOp<&Splinter> for Splinter {
62 type Output = Splinter;
63 #[inline]
64 fn $bitop(mut self, rhs: &Splinter) -> Self::Output {
65 $bitassign(&mut self, rhs);
66 self
67 }
68 }
69 impl<B: Deref<Target = [u8]>> $BitOp<SplinterRef<B>> for Splinter {
70 type Output = Splinter;
71 #[inline]
72 fn $bitop(mut self, rhs: SplinterRef<B>) -> Self::Output {
73 $bitassign(&mut self, rhs);
74 self
75 }
76 }
77 impl<B: Deref<Target = [u8]>> $BitOp<&SplinterRef<B>> for Splinter {
78 type Output = Splinter;
79 #[inline]
80 fn $bitop(mut self, rhs: &SplinterRef<B>) -> Self::Output {
81 $bitassign(&mut self, rhs);
82 self
83 }
84 }
85 impl<B: Deref<Target = [u8]>> $BitOp<SplinterRef<B>> for &Splinter {
86 type Output = Splinter;
87 #[inline]
88 fn $bitop(self, rhs: SplinterRef<B>) -> Self::Output {
89 $BitOp::$bitop(self.clone(), rhs)
90 }
91 }
92 impl<B: Deref<Target = [u8]>> $BitOp<&SplinterRef<B>> for &Splinter {
93 type Output = Splinter;
94 #[inline]
95 fn $bitop(self, rhs: &SplinterRef<B>) -> Self::Output {
96 $BitOp::$bitop(self.clone(), rhs)
97 }
98 }
99 impl<B: Deref<Target = [u8]>> $BitOp<CowSplinter<B>> for Splinter {
100 type Output = Splinter;
101 #[inline]
102 fn $bitop(self, rhs: CowSplinter<B>) -> Self::Output {
103 $BitOp::$bitop(&self, &rhs)
104 }
105 }
106 impl<B: Deref<Target = [u8]>> $BitOp<CowSplinter<B>> for &Splinter {
107 type Output = Splinter;
108 #[inline]
109 fn $bitop(self, rhs: CowSplinter<B>) -> Self::Output {
110 $BitOp::$bitop(self, &rhs)
111 }
112 }
113 impl<B: Deref<Target = [u8]>> $BitOp<&CowSplinter<B>> for Splinter {
114 type Output = Splinter;
115 #[inline]
116 fn $bitop(self, rhs: &CowSplinter<B>) -> Self::Output {
117 $BitOp::$bitop(&self, rhs)
118 }
119 }
120 impl<B: Deref<Target = [u8]>> $BitOp<&CowSplinter<B>> for &Splinter {
121 type Output = Splinter;
122 fn $bitop(self, rhs: &CowSplinter<B>) -> Self::Output {
123 match rhs {
124 CowSplinter::Ref(inner) => $BitOp::$bitop(self, inner),
125 CowSplinter::Owned(inner) => $BitOp::$bitop(self, inner),
126 }
127 }
128 }
129 };
130}
131
132macro_rules! unary_bitassign {
133 ($BitOpAssign:tt, $bitassign:ident) => {
134 impl $BitOpAssign<&Splinter> for Splinter {
135 #[inline]
136 fn $bitassign(&mut self, rhs: &Splinter) {
137 $BitOpAssign::$bitassign(self.inner_mut(), rhs.inner())
138 }
139 }
140 impl<B: Deref<Target = [u8]>> $BitOpAssign<SplinterRef<B>> for Splinter {
141 #[inline]
142 fn $bitassign(&mut self, rhs: SplinterRef<B>) {
143 $BitOpAssign::$bitassign(self.inner_mut(), &rhs.load_unchecked())
144 }
145 }
146 impl<B: Deref<Target = [u8]>> $BitOpAssign<&SplinterRef<B>> for Splinter {
147 #[inline]
148 fn $bitassign(&mut self, rhs: &SplinterRef<B>) {
149 $BitOpAssign::$bitassign(self.inner_mut(), &rhs.load_unchecked())
150 }
151 }
152 impl<B: Deref<Target = [u8]>> $BitOpAssign<CowSplinter<B>> for Splinter {
153 fn $bitassign(&mut self, rhs: CowSplinter<B>) {
154 match rhs {
155 CowSplinter::Ref(splinter_ref) => $BitOpAssign::$bitassign(self, splinter_ref),
156 CowSplinter::Owned(splinter) => $BitOpAssign::$bitassign(self, splinter),
157 }
158 }
159 }
160 impl<B: Deref<Target = [u8]>> $BitOpAssign<&CowSplinter<B>> for Splinter {
161 fn $bitassign(&mut self, rhs: &CowSplinter<B>) {
162 match rhs {
163 CowSplinter::Ref(splinter_ref) => $BitOpAssign::$bitassign(self, splinter_ref),
164 CowSplinter::Owned(splinter) => $BitOpAssign::$bitassign(self, splinter),
165 }
166 }
167 }
168 };
169}
170
171binary_bitop!(BitOr, bitor, BitOrAssign::bitor_assign);
172unary_bitassign!(BitOrAssign, bitor_assign);
173
174binary_bitop!(BitAnd, bitand, BitAndAssign::bitand_assign);
175unary_bitassign!(BitAndAssign, bitand_assign);
176
177binary_bitop!(BitXor, bitxor, BitXorAssign::bitxor_assign);
178unary_bitassign!(BitXorAssign, bitxor_assign);
179
180binary_bitop!(Sub, sub, SubAssign::sub_assign);
181unary_bitassign!(SubAssign, sub_assign);
182
183impl BitOr<&Splinter> for &Splinter {
184 type Output = Splinter;
185 fn bitor(self, rhs: &Splinter) -> Self::Output {
186 if rhs.cardinality() > self.cardinality() {
188 let mut result = rhs.clone();
189 result.inner_mut().bitor_assign(self.inner());
190 result
191 } else {
192 let mut result = self.clone();
193 result.inner_mut().bitor_assign(rhs.inner());
194 result
195 }
196 }
197}
198
199impl BitOr<Splinter> for &Splinter {
200 type Output = Splinter;
201 fn bitor(self, rhs: Splinter) -> Self::Output {
202 rhs | self
203 }
204}
205
206impl BitOrAssign<Splinter> for Splinter {
207 fn bitor_assign(&mut self, mut rhs: Splinter) {
208 if rhs.cardinality() > self.cardinality() {
210 mem::swap(self, &mut rhs);
211 }
212 self.inner_mut().bitor_assign(rhs.inner())
213 }
214}
215
216impl BitAnd<&Splinter> for &Splinter {
217 type Output = Splinter;
218 fn bitand(self, rhs: &Splinter) -> Self::Output {
219 if rhs.cardinality() < self.cardinality() {
221 let mut result = rhs.clone();
222 result.inner_mut().bitand_assign(self.inner());
223 result
224 } else {
225 let mut result = self.clone();
226 result.inner_mut().bitand_assign(rhs.inner());
227 result
228 }
229 }
230}
231
232impl BitAnd<Splinter> for &Splinter {
233 type Output = Splinter;
234 fn bitand(self, rhs: Splinter) -> Self::Output {
235 rhs & self
236 }
237}
238
239impl BitAndAssign<Splinter> for Splinter {
240 fn bitand_assign(&mut self, mut rhs: Splinter) {
241 if rhs.cardinality() < self.cardinality() {
243 mem::swap(self, &mut rhs);
244 }
245 self.inner_mut().bitand_assign(rhs.inner())
246 }
247}
248
249impl BitXor<&Splinter> for &Splinter {
250 type Output = Splinter;
251 fn bitxor(self, rhs: &Splinter) -> Self::Output {
252 let mut result = self.clone();
253 result.inner_mut().bitxor_assign(rhs.inner());
254 result
255 }
256}
257
258impl BitXor<Splinter> for &Splinter {
259 type Output = Splinter;
260 fn bitxor(self, rhs: Splinter) -> Self::Output {
261 rhs ^ self
262 }
263}
264
265impl BitXorAssign<Splinter> for Splinter {
266 fn bitxor_assign(&mut self, rhs: Splinter) {
267 self.inner_mut().bitxor_assign(rhs.inner())
268 }
269}
270
271impl Sub<&Splinter> for &Splinter {
272 type Output = Splinter;
273 fn sub(self, rhs: &Splinter) -> Self::Output {
274 let mut result = self.clone();
275 result.inner_mut().sub_assign(rhs.inner());
276 result
277 }
278}
279
280impl Sub<Splinter> for &Splinter {
281 type Output = Splinter;
282 fn sub(self, rhs: Splinter) -> Self::Output {
283 self - &rhs
284 }
285}
286
287impl SubAssign<Splinter> for Splinter {
288 fn sub_assign(&mut self, rhs: Splinter) {
289 self.inner_mut().sub_assign(rhs.inner())
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use std::ops::{
296 BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign,
297 };
298
299 use itertools::Itertools;
300 use proptest::collection::{hash_set, vec};
301 use proptest::proptest;
302
303 use crate::testutil::{mksplinter_cow, mksplinter_ref};
304 use crate::{Optimizable, Splinter, testutil::mksplinter, traits::Cut};
305
306 macro_rules! exercise_bitop {
307 ($a:expr, $b:expr, $seta:expr, $setb:expr, $op_method:ident, $hashset_method:ident) => {
308 let expected: Splinter = $seta.$hashset_method(&$setb).copied().collect();
309
310 assert_eq!((&$a).$op_method(&$b), expected, "&a, &b");
311 assert_eq!((&$a).$op_method($b.clone()), expected, "&a, b");
312 assert_eq!($a.clone().$op_method(&$b), expected, "a, &b");
313 assert_eq!($a.clone().$op_method($b.clone()), expected, "a, b");
314 };
315 }
316
317 macro_rules! exercise_bitop_assign {
318 ($a:expr, $b:expr, $seta:expr, $setb:expr, $op_assign_method:ident, $hashset_method:ident) => {
319 let expected: Splinter = $seta.$hashset_method(&$setb).copied().collect();
320
321 let mut c = $a.clone();
322 c.$op_assign_method($b.clone());
323 assert_eq!(c, expected, "c assign b");
324
325 let mut c = $a.clone();
326 c.$op_assign_method(&$b);
327 assert_eq!(c, expected, "c assign &b");
328 };
329 }
330
331 macro_rules! gen_bitop_test {
332 ($test_name:ident, $make_a:path, $make_b:path) => {
333 proptest! {
334 #[test]
335 fn $test_name(
336 seta in hash_set(0u32..16384, 0..1024),
337 setb in hash_set(0u32..16384, 0..1024),
338 ) {
339 let a = $make_a(seta.clone());
340 let b = $make_b(setb.clone());
341 exercise_bitop!(a, b, seta, setb, bitor, union);
342 exercise_bitop!(a, b, seta, setb, bitand, intersection);
343 exercise_bitop!(a, b, seta, setb, bitxor, symmetric_difference);
344 exercise_bitop!(a, b, seta, setb, sub, difference);
345 }
346 }
347 };
348 }
349
350 macro_rules! gen_bitop_assign_test {
351 ($test_name:ident, $make_b:path) => {
352 proptest! {
353 #[test]
354 fn $test_name(
355 optimize: bool,
356 seta in hash_set(0u32..16384, 0..1024),
357 setb in hash_set(0u32..16384, 0..1024),
358 ) {
359 let mut a = Splinter::from_iter(seta.clone());
360 let b = $make_b(setb.clone());
361 if optimize {
362 a.optimize();
363 }
364 exercise_bitop_assign!(a, b, seta, setb, bitor_assign, union);
365 exercise_bitop_assign!(a, b, seta, setb, bitand_assign, intersection);
366 exercise_bitop_assign!(a, b, seta, setb, bitxor_assign, symmetric_difference);
367 exercise_bitop_assign!(a, b, seta, setb, sub_assign, difference);
368 }
369 }
370 };
371 }
372
373 gen_bitop_test!(test_ops_s_s, Splinter::from_iter, Splinter::from_iter);
374 gen_bitop_test!(test_ops_s_sr, Splinter::from_iter, mksplinter_ref);
375 gen_bitop_test!(test_ops_s_sc, Splinter::from_iter, mksplinter_cow);
376
377 gen_bitop_test!(test_ops_sr_sr, mksplinter_ref, mksplinter_ref);
378 gen_bitop_test!(test_ops_sr_sc, mksplinter_ref, mksplinter_cow);
379
380 gen_bitop_test!(test_ops_sc_s, mksplinter_cow, Splinter::from_iter);
381 gen_bitop_test!(test_ops_sc_sr, mksplinter_cow, mksplinter_ref);
382
383 gen_bitop_assign_test!(test_ops_splinter_splinter_assign, Splinter::from_iter);
384 gen_bitop_assign_test!(test_ops_splinter_splinterref_assign, mksplinter_ref);
385 gen_bitop_assign_test!(test_ops_splinter_splintercow_assign, mksplinter_cow);
386
387 proptest! {
388 #[test]
389 fn test_splinter_equality_proptest(values in vec(0u32..16384, 0..1024)) {
390 let mut a = mksplinter(&values);
391 a.optimize();
392 let b = mksplinter(&values);
393 assert!(a == b)
394 }
395
396 #[test]
397 fn test_splinter_equality_ref_proptest(values in vec(0u32..16384, 0..1024)) {
398 let mut a = mksplinter(&values);
399 a.optimize();
400 let b = mksplinter(&values).encode_to_splinter_ref();
401 assert!(a == b)
402 }
403
404 #[test]
405 fn test_splinter_equality_proptest_2(
406 a in vec(0u32..16384, 0..1024),
407 b in vec(0u32..16384, 0..1024),
408 ) {
409 let expected = itertools::equal(a.iter().sorted().dedup(), b.iter().sorted().dedup());
410
411 let mut a = mksplinter(&a);
412 a.optimize();
413 let b = mksplinter(&b);
414
415 assert!((a == b) == expected)
416 }
417
418 #[test]
419 fn test_splinter_equality_ref_proptest_2(
420 a in vec(0u32..16384, 0..1024),
421 b in vec(0u32..16384, 0..1024),
422 ) {
423 let expected = itertools::equal(a.iter().sorted().dedup(), b.iter().sorted().dedup());
424
425 let mut a = mksplinter(&a);
426 a.optimize();
427 let b = mksplinter(&b).encode_to_splinter_ref();
428
429 assert!((a == b) == expected)
430 }
431
432 #[test]
433 fn test_bitor_assign_proptest(
434 optimize: bool,
435 a in hash_set(0u32..16384, 0..1024),
436 b in hash_set(0u32..16384, 0..1024),
437 ) {
438 let mut set: Splinter = a.iter().copied().collect();
439 let other: Splinter = b.iter().copied().collect();
440
441 if optimize {
442 set.optimize();
443 }
444
445 let expected: Splinter = a.union(&b).copied().collect();
446 set |= other;
447 assert!(set == expected)
448 }
449
450 #[test]
451 fn test_cut_proptest(
452 optimize: bool,
453 a in hash_set(0u32..16384, 0..1024),
454 b in hash_set(0u32..16384, 0..1024),
455 ) {
456 let mut source: Splinter = a.iter().copied().collect();
457 let other: Splinter = b.iter().copied().collect();
458
459 if optimize {
460 source.optimize();
461 }
462
463 let expected_intersection: Splinter = a.intersection(&b).copied().collect();
464 let expected_remaining: Splinter = a.difference(&b).copied().collect();
465
466 let actual_intersection = source.cut(&other);
467
468 assert_eq!(actual_intersection,expected_intersection);
469 assert_eq!(source,expected_remaining);
470 }
471
472 #[test]
473 fn test_bitor_ref_proptest(
474 optimize: bool,
475 a in hash_set(0u32..16384, 0..1024),
476 b in hash_set(0u32..16384, 0..1024),
477 ) {
478 let mut set: Splinter = a.iter().copied().collect();
479 let other_ref = Splinter::from_iter(b.clone()).encode_to_splinter_ref();
480
481 if optimize {
482 set.optimize();
483 }
484
485 let expected: Splinter = a.union(&b).copied().collect();
486 set |= other_ref;
487 assert!(set == expected)
488 }
489
490 #[test]
491 fn test_cut_ref_proptest(
492 optimize: bool,
493 a in hash_set(0u32..16384, 0..1024),
494 b in hash_set(0u32..16384, 0..1024),
495 ) {
496 let mut source: Splinter = a.iter().copied().collect();
497 let other_ref = Splinter::from_iter(b.clone()).encode_to_splinter_ref();
498
499 if optimize {
500 source.optimize();
501 }
502
503 let expected_intersection: Splinter = a.intersection(&b).copied().collect();
504 let expected_remaining: Splinter = a.difference(&b).copied().collect();
505
506 let actual_intersection = source.cut(&other_ref);
507
508 assert_eq!(actual_intersection,expected_intersection);
509 assert_eq!(source,expected_remaining);
510 }
511 }
512}