int_interval_stack/
stack_window.rs1use std::num::NonZeroUsize;
2
3use int_interval::traits::{COStartLenConstruct, IntCO, IntPrimitive};
4use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
5
6use crate::{HeightRun, IntCOStack};
7
8#[derive(Debug, Clone, Copy)]
9pub struct StackWindow<'a, I>
10where
11 I: IntCO,
12{
13 pub(crate) stack: &'a IntCOStack<I>,
14 pub(crate) interval: I,
15 pub(crate) point_start: usize,
17 pub(crate) point_end: usize,
19 pub(crate) height_at_start: usize,
21}
22
23impl<'a, I> StackWindow<'a, I>
24where
25 I: IntCO,
26{
27 pub(crate) fn new(stack: &'a IntCOStack<I>, interval: I) -> Self {
28 let points = stack.change_points();
29
30 let window_start = interval.start();
31 let window_end = interval.end_excl();
32
33 let point_start = points.partition_point(|point| point.at <= window_start);
34 let point_end =
35 point_start + points[point_start..].partition_point(|point| point.at < window_end);
36
37 let height_at_start = point_start
38 .checked_sub(1)
39 .map_or(0, |index| points[index].height_after);
40
41 Self {
42 stack,
43 interval,
44 point_start,
45 point_end,
46 height_at_start,
47 }
48 }
49
50 #[inline]
51 pub const fn stack(&self) -> &'a IntCOStack<I> {
52 self.stack
53 }
54
55 #[inline]
56 pub const fn interval(&self) -> &I {
57 &self.interval
58 }
59
60 #[inline]
73 fn height_run_count(&self) -> usize {
74 self.point_end - self.point_start + 1
75 }
76
77 #[inline]
95 fn height_run_at(&self, run_index: usize) -> HeightRun<I> {
96 debug_assert!(run_index < self.height_run_count());
97
98 let points = self.stack.change_points();
99
100 let point_index = self.point_start + run_index;
101
102 let start = if run_index == 0 {
103 self.interval.start()
104 } else {
105 points[point_index - 1].at
106 };
107
108 let end_excl = if point_index < self.point_end {
109 points[point_index].at
110 } else {
111 self.interval.end_excl()
112 };
113
114 let height = if run_index == 0 {
115 self.height_at_start
116 } else {
117 points[point_index - 1].height_after
118 };
119
120 HeightRun {
121 interval: unsafe { I::new_unchecked(start, end_excl) },
126 height,
127 }
128 }
129}
130
131impl<I> StackWindow<'_, I>
132where
133 I: IntCO,
134{
135 #[inline]
141 pub fn iter_height_runs(
142 &self,
143 ) -> impl DoubleEndedIterator<Item = HeightRun<I>> + ExactSizeIterator {
144 (0..self.height_run_count()).map(move |run_index| self.height_run_at(run_index))
145 }
146}
147
148impl<I> StackWindow<'_, I>
149where
150 I: IntCO + Send + Sync,
151{
152 #[inline]
158 pub fn par_iter_height_runs(&self) -> impl IndexedParallelIterator<Item = HeightRun<I>> {
159 (0..self.height_run_count())
160 .into_par_iter()
161 .map(move |run_index| self.height_run_at(run_index))
162 }
163}
164
165#[derive(Debug, Clone)]
174pub(crate) struct WindowIter<'a, I>
175where
176 I: IntCO,
177{
178 pub(crate) stack: &'a IntCOStack<I>,
179 pub(crate) from: I::CoordType,
181 pub(crate) interval: I,
183 pub(crate) point_start: usize,
185 pub(crate) point_end: usize,
187 pub(crate) height_at_start: usize,
189 pub(crate) remaining: usize,
191 pub(crate) total_count: usize,
193 pub(crate) consumed_back: usize,
195}
196
197impl<'a, I> WindowIter<'a, I>
198where
199 I: IntCO + COStartLenConstruct + Copy,
200{
201 pub(crate) fn new(
205 stack: &'a IntCOStack<I>,
206 from: I::CoordType,
207 len: I::MeasureType,
208 count: NonZeroUsize,
209 ) -> Self {
210 let interval = I::checked_from_start_len(from, len)
211 .expect("validated window count guarantees a representable first window");
212
213 let sw = StackWindow::new(stack, interval);
214
215 Self {
216 stack,
217 from,
218 interval,
219 point_start: sw.point_start,
220 point_end: sw.point_end,
221 height_at_start: sw.height_at_start,
222 remaining: count.get(),
223 total_count: count.get(),
224 consumed_back: 0,
225 }
226 }
227
228 #[inline]
237 fn advance(&mut self) {
238 debug_assert!(self.remaining > 0);
239
240 let new_start = self
241 .interval
242 .start()
243 .checked_next()
244 .expect("remaining > 0 guarantees the next start coordinate fits");
245 let new_end = self
246 .interval
247 .end_excl()
248 .checked_next()
249 .expect("remaining > 0 guarantees the next end coordinate fits");
250
251 let new_interval = unsafe { I::new_unchecked(new_start, new_end) };
255
256 let points = self.stack.change_points();
257
258 while self.point_start < points.len() && points[self.point_start].at <= new_start {
260 self.height_at_start = points[self.point_start].height_after;
261 self.point_start += 1;
262 }
263
264 while self.point_end < points.len() && points[self.point_end].at < new_end {
266 self.point_end += 1;
267 }
268
269 self.interval = new_interval;
270 self.remaining -= 1;
271 }
272}
273
274impl<'a, I> Iterator for WindowIter<'a, I>
275where
276 I: IntCO + COStartLenConstruct + Copy,
277{
278 type Item = StackWindow<'a, I>;
279
280 #[inline]
281 fn next(&mut self) -> Option<Self::Item> {
282 if self.remaining == 0 {
283 return None;
284 }
285 let window = StackWindow {
286 stack: self.stack,
287 interval: self.interval,
288 point_start: self.point_start,
289 point_end: self.point_end,
290 height_at_start: self.height_at_start,
291 };
292 self.advance();
293 Some(window)
294 }
295
296 #[inline]
297 fn size_hint(&self) -> (usize, Option<usize>) {
298 (self.remaining, Some(self.remaining))
299 }
300}
301
302impl<'a, I> ExactSizeIterator for WindowIter<'a, I>
303where
304 I: IntCO + COStartLenConstruct + Copy,
305{
306 #[inline]
307 fn len(&self) -> usize {
308 self.remaining
309 }
310}
311
312#[cfg(test)]
313mod tests_for_window_iter;
314
315#[cfg(test)]
316mod tests_for_new;
317
318#[cfg(test)]
319mod tests_for_height_run_at;
320
321#[cfg(test)]
322mod tests_for_iter_height_runs;