vecxe 0.1.0

Utility functions for vec
Documentation
pub trait WindowedExt<'a, T: 'a> {
    type IterBy: Iterator<Item = &'a [T]> + DoubleEndedIterator + ExactSizeIterator;
    fn sliding_windows_by(&'a self, size: usize, step: usize) -> Self::IterBy;
}

impl<'a, T: 'a> WindowedExt<'a, T> for [T] {
    type IterBy = SlidingBy<'a, T>;

    #[inline]
    fn sliding_windows_by(&'a self, size: usize, step: usize) -> Self::IterBy {
        SlidingBy::new(self, size, step)
    }
}

pub struct SlidingBy<'a, T> {
    slice: &'a [T],
    size: usize,
    step: usize,
    k_front: usize,
    k_back: usize,
    count: usize,
}

impl<'a, T> SlidingBy<'a, T> {
    pub fn new(slice: &'a [T], size: usize, step: usize) -> Self {
        let len = slice.len();
        let step = step.max(1);
        let count = if size == 0 || len < size {
            0
        } else {
            // n = 1 + floor((len - size) / step)
            1 + (len - size) / step
        };

        Self {
            slice,
            size,
            step,
            k_front: 0,
            k_back: count,
            count,
        }
    }

    #[inline]
    fn start_of(&self, k: usize) -> usize {
        k * self.step
    }
}

impl<'a, T> Iterator for SlidingBy<'a, T> {
    type Item = &'a [T];

    fn next(&mut self) -> Option<Self::Item> {
        if self.k_front >= self.k_back {
            return None;
        }
        let start = self.start_of(self.k_front);
        let end = start + self.size;
        self.k_front += 1;
        self.slice.get(start..end)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.k_back.saturating_sub(self.k_front);
        (rem, Some(rem))
    }
}

impl<'a, T> DoubleEndedIterator for SlidingBy<'a, T> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.k_front >= self.k_back {
            return None;
        }
        self.k_back -= 1;
        let start = self.start_of(self.k_back);
        let end = start + self.size;
        self.slice.get(start..end)
    }
}

impl<'a, T> ExactSizeIterator for SlidingBy<'a, T> {
    #[inline]
    fn len(&self) -> usize {
        self.k_back - self.k_front
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_sliding_by_step_2() {
        let v = vec![10, 20, 30, 40, 50, 60, 70];
        let mut windows = v.sliding_windows_by(3, 2);
        assert_eq!(windows.next(), Some([10, 20, 30].as_slice()));
        assert_eq!(windows.next(), Some([30, 40, 50].as_slice()));
        assert_eq!(windows.next(), Some([50, 60, 70].as_slice()));
        assert_eq!(windows.next(), None);
    }
}