Skip to main content

int_interval_stack/int_co_stack/
impls_for_windows.rs

1use int_interval::traits::{COStartLenConstruct, IntPrimitive};
2use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
3
4use super::*;
5
6#[inline]
7fn window_count<I>(from: I::CoordType, to: I::CoordType, len: I::MeasureType) -> Option<usize>
8where
9    I: IntCO + COStartLenConstruct,
10    I::MeasureType: TryInto<usize>,
11{
12    if len == I::MeasureType::zero() {
13        return None;
14    }
15
16    let domain = I::try_new(from, to)?;
17    let remaining = domain.len().checked_sub(len)?;
18    let count = remaining.checked_add(I::MeasureType::one())?;
19
20    count.try_into().ok()
21}
22
23#[inline]
24fn start_at<I>(from: I::CoordType, index: usize) -> Option<I::CoordType>
25where
26    I: IntCO + COStartLenConstruct,
27{
28    if index == 0 {
29        return Some(from);
30    }
31
32    let offset = I::MeasureType::checked_from(index)?;
33
34    I::checked_from_start_len(from, offset).map(|interval| interval.end_excl())
35}
36
37#[inline]
38fn window_at<'a, I>(
39    stack: &'a IntCOStack<I>,
40    from: I::CoordType,
41    len: I::MeasureType,
42    index: usize,
43) -> Option<StackWindow<'a, I>>
44where
45    I: IntCO + COStartLenConstruct + Copy,
46{
47    let start = start_at::<I>(from, index)?;
48    let interval = I::checked_from_start_len(start, len)?;
49
50    Some(StackWindow::new(stack, interval))
51}
52
53impl<I> IntCOStack<I>
54where
55    I: IntCO + COStartLenConstruct + Copy,
56    I::MeasureType: TryInto<usize>,
57{
58    /// Iterates over all fixed-length windows fully contained in `[from, to)`.
59    ///
60    /// Window starts advance by one coordinate unit:
61    ///
62    /// ```text
63    /// [from,     from + len)
64    /// [from + 1, from + 1 + len)
65    /// ...
66    /// ```
67    ///
68    /// Returns an empty iterator when:
69    ///
70    /// - `from >= to`;
71    /// - `len == 0`;
72    /// - `len` is greater than the measure of `[from, to)`;
73    /// - the window count cannot be represented as `usize`.
74    #[inline]
75    pub fn iter_windows(
76        &self,
77        from: I::CoordType,
78        to: I::CoordType,
79        len: I::MeasureType,
80    ) -> impl DoubleEndedIterator<Item = StackWindow<'_, I>> + ExactSizeIterator {
81        let count = window_count::<I>(from, to, len).unwrap_or(0);
82
83        (0..count).map(move |index| {
84            window_at(self, from, len, index)
85                .expect("validated window index must produce a representable window")
86        })
87    }
88
89    /// Iterates in parallel over all fixed-length windows fully contained in
90    /// `[from, to)`.
91    ///
92    /// The valid window-start range is represented as an indexed integer
93    /// range, allowing Rayon to split the work directly without a serial
94    /// producer or `par_bridge`.
95    #[inline]
96    pub fn par_iter_windows(
97        &self,
98        from: I::CoordType,
99        to: I::CoordType,
100        len: I::MeasureType,
101    ) -> impl IndexedParallelIterator<Item = StackWindow<'_, I>>
102    where
103        I: Send + Sync,
104    {
105        let count = window_count::<I>(from, to, len).unwrap_or(0);
106
107        (0..count).into_par_iter().map(move |index| {
108            window_at(self, from, len, index)
109                .expect("validated window index must produce a representable window")
110        })
111    }
112}
113
114#[cfg(test)]
115mod test_support;
116
117#[cfg(test)]
118mod tests_for_window_count;
119
120#[cfg(test)]
121mod tests_for_start_at;
122
123#[cfg(test)]
124mod tests_for_window_at;
125
126#[cfg(test)]
127mod tests_for_iter_windows;