sdset/duo/
symmetric_difference.rs1use std::cmp::Ordering;
2use crate::set::Set;
3use crate::{SetOperation, Collection};
4
5#[derive(Copy, Clone)]
25pub struct SymmetricDifference<'a, T: 'a> {
26 a: &'a [T],
27 b: &'a [T],
28}
29
30impl<'a, T> SymmetricDifference<'a, T> {
31 pub fn new(a: &'a Set<T>, b: &'a Set<T>) -> Self {
33 Self {
34 a: a.as_slice(),
35 b: b.as_slice(),
36 }
37 }
38}
39
40impl<'a, T: Ord> SymmetricDifference<'a, T> {
41 #[inline]
42 fn extend_collection<C, U, F>(mut self, output: &mut C, extend: F)
43 where C: Collection<U>,
44 F: Fn(&mut C, &'a [T])
45 {
46 loop {
47 match (self.a.first(), self.b.first()) {
48 (Some(a), Some(b)) => {
49 match a.cmp(b) {
50 Ordering::Less => {
51 let off = self.a.iter().take_while(|&e| e < b).count();
52 extend(output, &self.a[..off]);
53 self.a = &self.a[off..];
54 },
55 Ordering::Equal => {
56 let off = self.a.iter().zip(self.b.iter()).take_while(|(a, b)| a == b).count();
57 self.a = &self.a[off..];
58 self.b = &self.b[off..];
59 },
60 Ordering::Greater => {
61 let off = self.b.iter().take_while(|&e| e < a).count();
62 extend(output, &self.b[..off]);
63 self.b = &self.b[off..];
64 },
65 }
66 },
67 (None, Some(_)) => {
68 extend(output, self.b);
69 break;
70 },
71 (Some(_), None) => {
72 extend(output, self.a);
73 break;
74 },
75 (None, None) => break,
76 }
77 }
78 }
79}
80
81impl<'a, T: Ord + Clone> SetOperation<T> for SymmetricDifference<'a, T> {
82 fn extend_collection<C>(self, output: &mut C) where C: Collection<T> {
83 self.extend_collection(output, Collection::extend_from_slice)
84 }
85}
86
87impl<'a, T: Ord> SetOperation<&'a T> for SymmetricDifference<'a, T> {
88 fn extend_collection<C>(self, output: &mut C) where C: Collection<&'a T> {
89 self.extend_collection(output, Collection::extend)
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::set::{sort_dedup_vec, SetBuf};
97
98 quickcheck! {
99 fn qc_symmetric_difference(a: Vec<i32>, b: Vec<i32>) -> bool {
100 use std::collections::BTreeSet;
101 use std::iter::FromIterator;
102
103 let mut a = a;
104 let mut b = b;
105
106 sort_dedup_vec(&mut a);
107 sort_dedup_vec(&mut b);
108
109 let x: SetBuf<i32> = SymmetricDifference { a: &a, b: &b }.into_set_buf();
110
111 let a = BTreeSet::from_iter(a);
112 let b = BTreeSet::from_iter(b);
113 let y = a.symmetric_difference(&b);
114 let y: Vec<_> = y.cloned().collect();
115
116 x.as_slice() == y.as_slice()
117 }
118 }
119}
120
121#[cfg(all(feature = "unstable", test))]
122mod bench {
123 extern crate test;
124 use super::*;
125 use self::test::Bencher;
126 use crate::set::SetBuf;
127
128 #[bench]
129 fn two_slices_big(bench: &mut Bencher) {
130 let a: Vec<_> = (0..100).collect();
131 let b: Vec<_> = (1..101).collect();
132
133 bench.iter(|| {
134 let symmetric_difference_: SetBuf<i32> = SymmetricDifference { a: &a, b: &b }.into_set_buf();
135 test::black_box(|| symmetric_difference_);
136 });
137 }
138
139 #[bench]
140 fn two_slices_big2(bench: &mut Bencher) {
141 let a: Vec<_> = (0..100).collect();
142 let b: Vec<_> = (51..151).collect();
143
144 bench.iter(|| {
145 let symmetric_difference_: SetBuf<i32> = SymmetricDifference { a: &a, b: &b }.into_set_buf();
146 test::black_box(|| symmetric_difference_);
147 });
148 }
149
150 #[bench]
151 fn two_slices_big3(bench: &mut Bencher) {
152 let a: Vec<_> = (0..100).collect();
153 let b: Vec<_> = (100..200).collect();
154
155 bench.iter(|| {
156 let symmetric_difference_: SetBuf<i32> = SymmetricDifference { a: &a, b: &b }.into_set_buf();
157 test::black_box(|| symmetric_difference_);
158 });
159 }
160}