/
array_windows.rs
142 lines (131 loc) · 3.63 KB
/
array_windows.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use core::iter::FusedIterator;
/// An extension trait that provides the [`array_windows`] method for iterators.
///
/// [`array_windows`]: IterArrayWindows::array_windows
#[cfg_attr(docsrs, doc(cfg(feature = "array_windows")))]
pub trait IterArrayWindows: Iterator {
/// Returns an iterator over all contiguous windows of length `N`.
///
/// The windows overlap. If the iterator is shorter than `N`, the iterator
/// returns no values.
///
/// This adaptor clones the iterator elements so that they can be part of
/// successive windows, this makes this it most suited for iterators of
/// references and other values that are cheap to clone or copy.
///
/// # Panics
///
/// If called with `N = 0`.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use itermore::IterArrayWindows;
///
/// let mut iter = "rust".chars().array_windows();
/// assert_eq!(iter.next(), Some(['r', 'u']));
/// assert_eq!(iter.next(), Some(['u', 's']));
/// assert_eq!(iter.next(), Some(['s', 't']));
/// assert_eq!(iter.next(), None);
/// ```
///
/// ```
/// use itermore::IterArrayWindows;
///
/// let seq: &[i32] = &[0, 1, 1, 2, 3, 5, 8, 13];
/// for [x, y, z] in seq.iter().copied().array_windows() {
/// assert_eq!(x + y, z);
/// }
/// ```
#[inline]
fn array_windows<const N: usize>(self) -> ArrayWindows<Self, N>
where
Self: Sized,
Self::Item: Clone,
{
ArrayWindows::new(self)
}
}
impl<I: ?Sized> IterArrayWindows for I where I: Iterator {}
/// An iterator over all contiguous windows of length `N`.
///
/// This struct is created by the [`array_windows`] method on iterators. See its
/// documentation for more.
///
/// [`array_windows`]: IterArrayWindows::array_windows
#[cfg_attr(docsrs, doc(cfg(feature = "array_windows")))]
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ArrayWindows<I, const N: usize>
where
I: Iterator,
{
iter: I,
last: Option<[I::Item; N]>,
}
impl<I, const N: usize> ArrayWindows<I, N>
where
I: Iterator,
I::Item: Clone,
{
fn new(iter: I) -> Self {
assert!(N != 0, "window size must be non-zero");
Self { iter, last: None }
}
}
impl<I: Iterator, const N: usize> Iterator for ArrayWindows<I, N>
where
I: Iterator,
I::Item: Clone,
{
type Item = [I::Item; N];
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let Self { iter, last } = self;
match last {
Some(last) => {
let item = iter.next()?;
last.rotate_left(1);
if let Some(end) = last.last_mut() {
*end = item;
}
Some(last.clone())
}
None => {
let tmp = arrays::from_iter(iter).ok()?;
*last = Some(tmp.clone());
Some(tmp)
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.iter.size_hint();
(
lower.saturating_sub(N - 1),
upper.map(|n| n.saturating_sub(N - 1)),
)
}
#[inline]
fn count(self) -> usize {
self.iter.count().saturating_sub(N - 1)
}
}
impl<I, const N: usize> ExactSizeIterator for ArrayWindows<I, N>
where
I: ExactSizeIterator,
I::Item: Clone,
{
#[inline]
fn len(&self) -> usize {
self.iter.len().saturating_sub(N - 1)
}
}
impl<I, const N: usize> FusedIterator for ArrayWindows<I, N>
where
I: FusedIterator + Clone,
I::Item: Clone,
{
}