range_set_blaze/
unsorted_disjoint.rs1use crate::{Integer, SortedDisjoint, SortedStarts};
2#[cfg(not(debug_assertions))]
3use core::marker::PhantomData;
4use core::{
5 cmp::{max, min},
6 iter::FusedIterator,
7 ops::RangeInclusive,
8};
9use num_traits::Zero;
10
11#[must_use = "iterators are lazy and do nothing unless consumed"]
12#[allow(clippy::redundant_pub_crate)]
13pub(crate) struct UnsortedDisjoint<T, I> {
14 iter: I,
15 option_range: Option<RangeInclusive<T>>,
16 min_value_plus_2: T,
17}
18
19impl<T, I> UnsortedDisjoint<T, I>
20where
21 T: Integer,
22 I: Iterator<Item = RangeInclusive<T>>, {
24 #[inline]
25 pub(crate) fn new(iter: I) -> Self {
26 Self {
27 iter,
28 option_range: None,
29 min_value_plus_2: T::min_value().add_one().add_one(),
30 }
31 }
32}
33
34impl<T, I> FusedIterator for UnsortedDisjoint<T, I>
35where
36 T: Integer,
37 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
38{
39}
40
41impl<T, I> Iterator for UnsortedDisjoint<T, I>
42where
43 T: Integer,
44 I: Iterator<Item = RangeInclusive<T>>,
45{
46 type Item = RangeInclusive<T>;
47
48 fn next(&mut self) -> Option<Self::Item> {
49 loop {
50 let Some(range) = self.iter.next() else {
51 return self.option_range.take();
52 };
53 let (next_start, next_end) = range.into_inner();
54 if next_start > next_end {
55 continue;
56 }
57 let Some(self_range) = self.option_range.clone() else {
58 self.option_range = Some(next_start..=next_end);
59 continue;
60 };
61
62 let (self_start, self_end) = self_range.into_inner();
63 if (next_start >= self.min_value_plus_2 && self_end <= next_start.sub_one().sub_one())
64 || (self_start >= self.min_value_plus_2
65 && next_end <= self_start.sub_one().sub_one())
66 {
67 let result = Some(self_start..=self_end);
68 self.option_range = Some(next_start..=next_end);
69 return result;
70 }
71 self.option_range = Some(min(self_start, next_start)..=max(self_end, next_end));
72 }
74 }
75
76 fn size_hint(&self) -> (usize, Option<usize>) {
79 let (lower, upper) = self.iter.size_hint();
80 let lower = min(lower, 1);
81 if self.option_range.is_some() {
82 (lower, upper.map(|x| x + 1))
83 } else {
84 (lower, upper)
85 }
86 }
87}
88
89#[must_use = "iterators are lazy and do nothing unless consumed"]
90#[allow(clippy::redundant_pub_crate)]
91pub(crate) struct SortedDisjointWithLenSoFar<T: Integer, I> {
92 iter: I,
93 len: <T as Integer>::SafeLen,
94}
95
96impl<T, I> SortedDisjointWithLenSoFar<T, I>
97where
98 T: Integer,
99 I: Iterator<Item = RangeInclusive<T>> + SortedDisjoint<T>,
100{
101 #[inline]
102 pub(crate) fn new(iter: I) -> Self {
103 Self {
104 iter,
105 len: T::SafeLen::zero(),
106 }
107 }
108}
109
110impl<T: Integer, I> SortedDisjointWithLenSoFar<T, I>
111where
112 I: SortedDisjoint<T>,
113{
114 pub(crate) const fn len_so_far(&self) -> <T as Integer>::SafeLen {
115 self.len
116 }
117}
118
119impl<T: Integer, I> FusedIterator for SortedDisjointWithLenSoFar<T, I> where
120 I: SortedDisjoint<T> + FusedIterator
121{
122}
123
124impl<T: Integer, I> Iterator for SortedDisjointWithLenSoFar<T, I>
125where
126 I: SortedDisjoint<T>,
127{
128 type Item = (T, T);
129
130 fn next(&mut self) -> Option<Self::Item> {
131 if let Some(range) = self.iter.next() {
132 let (start, end) = range.clone().into_inner();
133 debug_assert!(start <= end);
134 self.len += T::safe_len(&range);
135 Some((start, end))
136 } else {
137 None
138 }
139 }
140 fn size_hint(&self) -> (usize, Option<usize>) {
141 self.iter.size_hint()
142 }
143}
144
145#[derive(Clone, Debug)]
146#[must_use = "iterators are lazy and do nothing unless consumed"]
147pub struct AssumeSortedStarts<T, I> {
149 pub(crate) iter: I,
150 #[cfg(debug_assertions)]
151 last_start: Option<T>,
152 #[cfg(not(debug_assertions))]
153 last_start: PhantomData<T>,
154}
155
156impl<T, I> FusedIterator for AssumeSortedStarts<T, I>
157where
158 T: Integer,
159 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
160{
161}
162
163impl<T: Integer, I> SortedStarts<T> for AssumeSortedStarts<T, I> where
164 I: Iterator<Item = RangeInclusive<T>> + FusedIterator
165{
166}
167
168impl<T, I> AssumeSortedStarts<T, I>
169where
170 T: Integer,
171 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
172{
173 #[inline]
175 pub fn new<J: IntoIterator<IntoIter = I>>(iter: J) -> Self {
176 Self {
177 iter: iter.into_iter(),
178 #[cfg(debug_assertions)]
179 last_start: None,
180 #[cfg(not(debug_assertions))]
181 last_start: PhantomData,
182 }
183 }
184}
185
186impl<T, I> Iterator for AssumeSortedStarts<T, I>
187where
188 T: Integer,
189 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
190{
191 type Item = RangeInclusive<T>;
192
193 fn next(&mut self) -> Option<Self::Item> {
194 let r = self.iter.next();
195 #[cfg(debug_assertions)]
196 if let Some(next) = &r {
197 let next_start = *next.start();
198 if let Some(last) = self.last_start {
199 assert!(
200 last <= next_start,
201 "AssumeSortedStarts contained items with starts which are not sorted: {last:?}<={next_start:?} is wrong"
202 );
203 }
204 self.last_start = Some(next_start);
205 }
206 r
207 }
208
209 fn size_hint(&self) -> (usize, Option<usize>) {
210 self.iter.size_hint()
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 #[cfg(debug_assertions)]
220 #[should_panic(
221 expected = "AssumeSortedStarts contained items with starts which are not sorted: 1<=0 is wrong"
222 )]
223 fn panic_if_unsorted_starts_in_assume_sorted_starts() {
224 AssumeSortedStarts::new([1..=10, 0..=20]).count();
225 }
226}