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