Skip to main content

segmap/set/ops/
symmetric_difference.rs

1use core::{cmp::Ordering::*, fmt::Debug, iter::FusedIterator};
2
3use crate::{map::Key, set::iterators::Iter, Segment, SegmentMap, SegmentSet};
4
5impl<T> SegmentSet<T> {
6    // TODO: into_difference_iter
7
8    pub fn symmetric_difference_iter<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T> {
9        SymmetricDifference {
10            iter_a: self.iter(),
11            prev_a: None,
12            iter_b: other.iter(),
13            prev_b: None,
14        }
15    }
16
17    // TODO: into_symmetric_difference
18
19    pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SegmentSet<&'a T>
20    where
21        T: Ord,
22    {
23        // Don't need to insert, since we know ranges produced by the iterator
24        // aren't overlapping
25        SegmentSet {
26            map: SegmentMap {
27                map: self
28                    .symmetric_difference_iter(other)
29                    .map(|r| (Key(r), ()))
30                    .collect(),
31                store: alloc::vec::Vec::new(),
32            },
33        }
34    }
35}
36
37/// Set Symmetric Difference
38impl<'a, T: Ord + Clone> core::ops::BitXor<&'a SegmentSet<T>> for &'a SegmentSet<T> {
39    type Output = SegmentSet<&'a T>;
40
41    // TODO: docs
42
43    /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet<T>`.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use std::collections::BTreeSet;
49    ///
50    /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect();
51    /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect();
52    ///
53    /// let result = &a ^ &b;
54    /// let result_vec: Vec<_> = result.into_iter().collect();
55    /// assert_eq!(result_vec, [1, 4]);
56    /// ```
57    fn bitxor(self, rhs: &'a SegmentSet<T>) -> SegmentSet<&'a T> {
58        self.symmetric_difference(rhs)
59    }
60}
61
62// TODO: BitXorAssign for symmetric difference? Maybe omit, unless a good use case comes up
63// /// Set in-place symmetric difference  // TODO: self.into_symmetric_difference() may be quicker for these?
64// impl<T: Ord + Clone> core::ops::BitXorAssign<&SegmentSet<T>> for SegmentSet<T> {
65//     fn bitxor_assign(&mut self, rhs: &SegmentSet<T>) {
66
67//     }
68// }
69// impl<T: Ord + Clone> core::ops::BitXorAssign<SegmentSet<T>> for SegmentSet<T> {
70//     fn sub_assign(&mut self, rhs: SegmentSet<T>) {
71//         for range in rhs.iter() {
72//             self.remove(range);
73//         }
74//     }
75// }
76
77#[derive(Debug, Clone)]
78pub struct SymmetricDifference<'a, T> {
79    iter_a: Iter<'a, T>,
80    prev_a: Option<Segment<&'a T>>,
81    iter_b: Iter<'a, T>,
82    prev_b: Option<Segment<&'a T>>,
83}
84
85// impl<T: fmt::Debug> fmt::Debug for SymmetricDifference<'_, T> {
86//     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87//         f.debug_tuple("SymmetricDifference").field(&self.).finish()
88//     }
89// }
90
91// impl<T> Clone for SymmetricDifference<'_, T> {
92//     fn clone(&self) -> Self {
93//         Self {
94
95//         }
96//     }
97// }
98
99impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
100    type Item = Segment<&'a T>;
101
102    fn next(&mut self) -> Option<Segment<&'a T>> {
103        let next_a = self
104            .prev_a
105            .take()
106            .or_else(|| self.iter_a.next().map(|x| x.as_ref()));
107
108        let next_b = self
109            .prev_b
110            .take()
111            .or_else(|| self.iter_b.next().map(|x| x.as_ref()));
112
113        // If one ran out, use the other
114        let mut next_a = match next_a {
115            Some(a) => a,
116            None => return next_b,
117        };
118        let mut next_b = match next_b {
119            Some(b) => b,
120            None => return Some(next_a),
121        };
122
123        // Otherwise, look for mutually exclusive items
124        loop {
125            // If `next_a` is fully before `next_b`, use it
126            // (and hold on to `next_b`)
127            if next_a.end.cmp_start(&next_b.start).is_gt() {
128                self.prev_b.insert(next_b);
129                return Some(next_b);
130            }
131
132            // Likewise the other way around
133            if next_a.start.cmp_end(&next_b.end).is_gt() {
134                self.prev_a.insert(next_a);
135                return Some(next_a);
136            }
137
138            // Otherwise, we have some overlap
139            match (next_a.start.cmp(&next_b.start), next_a.end.cmp(&next_b.end)) {
140                // Partial overlap, but `a` doesn't extend beyond `b`.
141                // Use the non-overlapped part of `a` and remember to remove
142                // the overlap from `b` for the next iteration.
143                (Less, Less) => {
144                    // When removing the overlapped region, use `replace` to
145                    // make sure we do it in order.
146                    next_b.start =
147                        core::mem::replace(&mut next_a.end, next_b.borrow_bound_before().unwrap())
148                            .borrow_after()
149                            .unwrap();
150                    self.prev_b.insert(next_b);
151                    return Some(next_a);
152                }
153
154                // Partial overlap where `a` extends just to the
155                // end of `b` (don't save `b`)
156                (Less, Equal) => {
157                    next_a.end = next_b.borrow_bound_before().unwrap();
158                    return Some(next_a);
159                }
160
161                // `a` extends beyond `b` in both directions.
162                // Use the part of `a` before `b` and store
163                // the part after.
164                (Less, Greater) => {
165                    self.prev_a.insert(Segment {
166                        start: next_b.borrow_bound_after().unwrap(),
167                        end: next_a.end,
168                    });
169                    next_a.end = next_b.borrow_bound_before().unwrap();
170                    return Some(next_a);
171                }
172
173                // `b` extends past `a`. Remove the overlap and loop
174                // (if necessary)
175                (Equal, Less) => {
176                    next_b.start = next_a.borrow_bound_after().unwrap();
177                    if let Some(a) = self.iter_a.next() {
178                        next_a = a.as_ref();
179                        continue;
180                    } else {
181                        // No more `a`s, just return this `b` part
182                        return Some(next_b);
183                    }
184                }
185
186                // Both exactly overlap each other. loop!
187                // (or return early because we're out of items in one)
188                (Equal, Equal) => {
189                    if let Some(a) = self.iter_a.next().map(|x| x.as_ref()) {
190                        next_a = a;
191                    } else {
192                        // But no more `a`s
193                        return Some(next_b);
194                    }
195                    if let Some(b) = self.iter_b.next().map(|x| x.as_ref()) {
196                        next_b = b;
197                    } else {
198                        // But no more `b`s
199                        return Some(next_a);
200                    }
201                    continue;
202                }
203
204                // Partial overlap, but some `b` past `a`
205                // Keep part of `a` and look for a new `b`
206                (Equal, Greater) => {
207                    next_a.start = next_b.borrow_bound_after().unwrap();
208                    if let Some(b) = self.iter_b.next().map(|x| x.as_ref()) {
209                        next_b = b;
210                    } else {
211                        return Some(next_b);
212                    }
213                    continue;
214                }
215
216                // `b` extends beyond `a` in both directions.
217                // Use the part of `b` before `a` and store
218                // the part after.
219                (Greater, Less) => {
220                    self.prev_b.insert(Segment {
221                        start: next_a.borrow_bound_after().unwrap(),
222                        end: next_b.end,
223                    });
224                    next_b.end = next_a.borrow_bound_before().unwrap();
225                    return Some(next_b);
226                }
227
228                // Partial overlap, where `b` extends before `a`, but they
229                // end together.
230                (Greater, Equal) => {
231                    next_b.end = next_a.borrow_bound_before().unwrap();
232                    return Some(next_b);
233                }
234
235                // Partial overlap, but `b` doesn't extend beyond `a`.
236                // Use the non-overlapped part of `b` and remember to remove
237                // the overlap from `a` for the next iteration.
238                (Greater, Greater) => {
239                    // When removing the overlapped region, use `replace` to
240                    // make sure we do it in order. (Similar to (Less, Less))
241                    next_a.start =
242                        core::mem::replace(&mut next_b.end, next_a.borrow_bound_before().unwrap())
243                            .borrow_after()
244                            .unwrap();
245                    self.prev_a.insert(next_a);
246                    return Some(next_b);
247                }
248            }
249        }
250    }
251
252    fn size_hint(&self) -> (usize, Option<usize>) {
253        (0, Some(self.iter_a.len() + self.iter_b.len()))
254    }
255
256    fn min(mut self) -> Option<Segment<&'a T>> {
257        self.next()
258    }
259}
260
261impl<T: Ord> FusedIterator for SymmetricDifference<'_, T> {}