int_interval_stack/int_co_stack/
impls_for_windows.rs1use std::num::NonZeroUsize;
2
3use either::Either;
4use int_interval::traits::{COStartLenConstruct, IntPrimitive};
5use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
6
7use super::*;
8use crate::stack_window::WindowIter;
9
10#[inline]
11fn window_count<I>(from: I::CoordType, to: I::CoordType, len: I::MeasureType) -> Option<usize>
12where
13 I: IntCO + COStartLenConstruct,
14 I::MeasureType: TryInto<usize>,
15{
16 if len == I::MeasureType::zero() {
17 return None;
18 }
19
20 let domain = I::try_new(from, to)?;
21 let remaining = domain.len().checked_sub(len)?;
22 let count = remaining.checked_add(I::MeasureType::one())?;
23
24 count.try_into().ok()
25}
26
27#[inline]
28fn start_at<I>(from: I::CoordType, index: usize) -> Option<I::CoordType>
29where
30 I: IntCO + COStartLenConstruct,
31{
32 if index == 0 {
33 return Some(from);
34 }
35
36 let offset = I::MeasureType::checked_from(index)?;
37
38 I::checked_from_start_len(from, offset).map(|interval| interval.end_excl())
39}
40
41#[inline]
42pub(crate) fn window_at<'a, I>(
43 stack: &'a IntCOStack<I>,
44 from: I::CoordType,
45 len: I::MeasureType,
46 index: usize,
47) -> Option<StackWindow<'a, I>>
48where
49 I: IntCO + COStartLenConstruct + Copy,
50{
51 let start = start_at::<I>(from, index)?;
52 let interval = I::checked_from_start_len(start, len)?;
53
54 Some(StackWindow::new(stack, interval))
55}
56
57impl<I> IntCOStack<I>
58where
59 I: IntCO + COStartLenConstruct + Copy,
60 I::MeasureType: TryInto<usize>,
61{
62 #[inline]
79 pub fn iter_windows(
80 &self,
81 from: I::CoordType,
82 to: I::CoordType,
83 len: I::MeasureType,
84 ) -> impl DoubleEndedIterator<Item = StackWindow<'_, I>> + ExactSizeIterator {
85 let count = window_count::<I>(from, to, len).unwrap_or(0);
86
87 let Some(count) = NonZeroUsize::new(count) else {
88 return Either::Left(std::iter::empty());
89 };
90
91 Either::Right(WindowIter::new(self, from, len, count))
92 }
93
94 #[inline]
101 pub fn par_iter_windows(
102 &self,
103 from: I::CoordType,
104 to: I::CoordType,
105 len: I::MeasureType,
106 ) -> impl IndexedParallelIterator<Item = StackWindow<'_, I>>
107 where
108 I: Send + Sync,
109 {
110 let count = window_count::<I>(from, to, len).unwrap_or(0);
111
112 (0..count).into_par_iter().map(move |index| {
113 window_at(self, from, len, index)
114 .expect("validated window index must produce a representable window")
115 })
116 }
117}
118
119impl<'a, I> DoubleEndedIterator for WindowIter<'a, I>
125where
126 I: IntCO + COStartLenConstruct + Copy,
127 I::MeasureType: TryInto<usize>,
128{
129 #[inline]
130 fn next_back(&mut self) -> Option<Self::Item> {
131 if self.remaining == 0 {
132 return None;
133 }
134
135 let back_index = self.total_count - self.consumed_back - 1;
136 self.consumed_back += 1;
137 self.remaining -= 1;
138
139 Some(
140 window_at(self.stack, self.from, self.interval.len(), back_index)
141 .expect("back index is always valid when remaining > 0"),
142 )
143 }
144}
145
146#[cfg(test)]
147mod test_support;
148
149#[cfg(test)]
150mod tests_for_window_count;
151
152#[cfg(test)]
153mod tests_for_start_at;
154
155#[cfg(test)]
156mod tests_for_window_at;
157
158#[cfg(test)]
159mod tests_for_iter_windows;