Skip to content

Commit 6f19676

Browse files
committed
Add Iterator::array_windows()
1 parent 442248d commit 6f19676

File tree

7 files changed

+222
-3
lines changed

7 files changed

+222
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use crate::iter::{ExactSizeIterator, Fuse, FusedIterator, Iterator, TrustedLen};
2+
3+
use crate::array;
4+
5+
/// An iterator over all contiguous windows of length `N`. The windows overlap.
6+
/// If the iterator is shorter than `N`, the iterator returns no values.
7+
///
8+
/// This `struct` is created by [`Iterator::array_windows`]. See its
9+
/// documentation for more.
10+
#[derive(Debug, Clone)]
11+
#[must_use = "iterators are lazy and do nothing unless consumed"]
12+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
13+
pub struct ArrayWindows<I, const N: usize>
14+
where
15+
I: Iterator,
16+
I::Item: Clone,
17+
{
18+
iter: Fuse<I>,
19+
last: Option<[I::Item; N]>,
20+
}
21+
22+
impl<I, const N: usize> ArrayWindows<I, N>
23+
where
24+
I: Iterator,
25+
I::Item: Clone,
26+
{
27+
#[inline]
28+
pub(in crate::iter) fn new(iter: I) -> Self {
29+
assert!(N != 0);
30+
Self { iter: iter.fuse(), last: None }
31+
}
32+
}
33+
34+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
35+
impl<I: Iterator, const N: usize> Iterator for ArrayWindows<I, N>
36+
where
37+
I: Iterator,
38+
I::Item: Clone,
39+
{
40+
type Item = [I::Item; N];
41+
42+
#[inline]
43+
fn next(&mut self) -> Option<Self::Item> {
44+
let Self { iter, last } = self;
45+
46+
match last {
47+
Some(last) => {
48+
let item = iter.next()?;
49+
last.rotate_left(1);
50+
if let Some(end) = last.last_mut() {
51+
*end = item;
52+
}
53+
Some(last.clone())
54+
}
55+
None => {
56+
let tmp = array::try_from_fn(|_| iter.next())?;
57+
*last = Some(tmp.clone());
58+
Some(tmp)
59+
}
60+
}
61+
}
62+
63+
#[inline]
64+
fn size_hint(&self) -> (usize, Option<usize>) {
65+
let (lower, upper) = self.iter.size_hint();
66+
// Keep infinite iterator size hint lower bound as `usize::MAX`
67+
if lower == usize::MAX {
68+
(lower, upper)
69+
} else {
70+
(lower.saturating_sub(N - 1), upper.map(|n| n.saturating_sub(N - 1)))
71+
}
72+
}
73+
74+
#[inline]
75+
fn count(self) -> usize {
76+
self.iter.count().saturating_sub(N - 1)
77+
}
78+
}
79+
80+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
81+
impl<I, const N: usize> FusedIterator for ArrayWindows<I, N>
82+
where
83+
I: FusedIterator,
84+
I::Item: Clone,
85+
{
86+
}
87+
88+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
89+
impl<I, const N: usize> ExactSizeIterator for ArrayWindows<I, N>
90+
where
91+
I: ExactSizeIterator,
92+
I::Item: Clone,
93+
{
94+
}
95+
96+
#[unstable(feature = "trusted_len", issue = "37572")]
97+
unsafe impl<I, const N: usize> TrustedLen for ArrayWindows<I, N>
98+
where
99+
I: TrustedLen,
100+
I::Item: Clone,
101+
{
102+
}

library/core/src/iter/adapters/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::iter::{InPlaceIterable, Iterator};
22
use crate::ops::{ControlFlow, Try};
33

4+
mod array_windows;
45
mod chain;
56
mod cloned;
67
mod copied;
@@ -30,6 +31,9 @@ pub use self::{
3031
scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
3132
};
3233

34+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
35+
pub use self::array_windows::ArrayWindows;
36+
3337
#[stable(feature = "iter_cloned", since = "1.1.0")]
3438
pub use self::cloned::Cloned;
3539

library/core/src/iter/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ pub use self::traits::{
393393

394394
#[stable(feature = "iter_zip", since = "1.59.0")]
395395
pub use self::adapters::zip;
396+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
397+
pub use self::adapters::ArrayWindows;
396398
#[stable(feature = "iter_cloned", since = "1.1.0")]
397399
pub use self::adapters::Cloned;
398400
#[stable(feature = "iter_copied", since = "1.36.0")]

library/core/src/iter/traits/iterator.rs

+47-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ use crate::cmp::{self, Ordering};
22
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
33

44
use super::super::TrustedRandomAccessNoCoerce;
5+
use super::super::{
6+
ArrayWindows, Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take,
7+
TakeWhile,
8+
};
59
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
610
use super::super::{FlatMap, Flatten};
711
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
8-
use super::super::{
9-
Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
10-
};
1112

1213
fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
1314

@@ -3057,6 +3058,49 @@ pub trait Iterator {
30573058
Cycle::new(self)
30583059
}
30593060

3061+
/// Returns an iterator over all contiguous windows of length `N`. The
3062+
/// windows overlap. If the iterator is shorter than `N`, the iterator
3063+
/// returns no values.
3064+
///
3065+
/// `array_windows` clones the iterator elements so that they can be part of
3066+
/// successive windows, this makes this it most suited for iterators of
3067+
/// references and other values that are cheap to clone.
3068+
///
3069+
/// # Panics
3070+
///
3071+
/// If called with `N = 0`.
3072+
///
3073+
/// # Examples
3074+
///
3075+
/// Basic usage:
3076+
///
3077+
/// ```
3078+
/// #![feature(iter_array_windows)]
3079+
///
3080+
/// let mut iter = "rust".chars().array_windows();
3081+
/// assert_eq!(iter.next(), Some(['r', 'u']));
3082+
/// assert_eq!(iter.next(), Some(['u', 's']));
3083+
/// assert_eq!(iter.next(), Some(['s', 't']));
3084+
/// assert_eq!(iter.next(), None);
3085+
/// ```
3086+
///
3087+
/// ```
3088+
/// #![feature(iter_array_windows)]
3089+
///
3090+
/// let seq: &[i32] = &[0, 1, 1, 2, 3, 5, 8, 13];
3091+
/// for [x, y, z] in seq.iter().copied().array_windows() {
3092+
/// assert_eq!(x + y, z);
3093+
/// }
3094+
/// ```
3095+
#[unstable(feature = "iter_array_windows", reason = "recently added", issue = "none")]
3096+
fn array_windows<const N: usize>(self) -> ArrayWindows<Self, N>
3097+
where
3098+
Self: Sized,
3099+
Self::Item: Clone,
3100+
{
3101+
ArrayWindows::new(self)
3102+
}
3103+
30603104
/// Sums the elements of an iterator.
30613105
///
30623106
/// Takes each element, adds them together, and returns the result.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use core::iter;
2+
3+
#[test]
4+
fn test_array_windows_infer() {
5+
let s = [0, 1, 0, 1, 0, 1];
6+
for [a, b] in s.iter().copied().array_windows() {
7+
assert_eq!(a + b, 1);
8+
}
9+
for [a, b, c, d] in s.iter().copied().array_windows() {
10+
assert_eq!(a + b + c + d, 2);
11+
}
12+
}
13+
14+
#[test]
15+
fn test_array_windows_size_hint() {
16+
let iter = (0..6).array_windows::<1>();
17+
assert_eq!(iter.size_hint(), (6, Some(6)));
18+
19+
let iter = (0..6).array_windows::<3>();
20+
assert_eq!(iter.size_hint(), (4, Some(4)));
21+
22+
let iter = (0..6).array_windows::<5>();
23+
assert_eq!(iter.size_hint(), (2, Some(2)));
24+
25+
let iter = (0..6).array_windows::<7>();
26+
assert_eq!(iter.size_hint(), (0, Some(0)));
27+
28+
let iter = (1..).array_windows::<2>();
29+
assert_eq!(iter.size_hint(), (usize::MAX, None));
30+
31+
let iter = (1..).filter(|x| x % 2 != 0).array_windows::<2>();
32+
assert_eq!(iter.size_hint(), (0, None));
33+
}
34+
35+
#[test]
36+
fn test_array_windows_count() {
37+
let iter = (0..6).array_windows::<1>();
38+
assert_eq!(iter.count(), 6);
39+
40+
let iter = (0..6).array_windows::<3>();
41+
assert_eq!(iter.count(), 4);
42+
43+
let iter = (0..6).array_windows::<5>();
44+
assert_eq!(iter.count(), 2);
45+
46+
let iter = (0..6).array_windows::<7>();
47+
assert_eq!(iter.count(), 0);
48+
49+
let iter = (0..6).filter(|x| x % 2 == 0).array_windows::<2>();
50+
assert_eq!(iter.count(), 2);
51+
52+
let iter = iter::empty::<i32>().array_windows::<2>();
53+
assert_eq!(iter.count(), 0);
54+
55+
let iter = [(); usize::MAX].iter().array_windows::<2>();
56+
assert_eq!(iter.count(), usize::MAX - 1);
57+
}
58+
59+
#[test]
60+
fn test_array_windows_nth() {
61+
let mut iter = (0..6).array_windows::<4>();
62+
assert_eq!(iter.nth(1), Some([1, 2, 3, 4]));
63+
assert_eq!(iter.nth(0), Some([2, 3, 4, 5]));
64+
assert_eq!(iter.nth(1), None);
65+
}

library/core/tests/iter/adapters/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod array_windows;
12
mod chain;
23
mod cloned;
34
mod copied;

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#![feature(slice_partition_dedup)]
6161
#![feature(int_log)]
6262
#![feature(iter_advance_by)]
63+
#![feature(iter_array_windows)]
6364
#![feature(iter_partition_in_place)]
6465
#![feature(iter_intersperse)]
6566
#![feature(iter_is_partitioned)]

0 commit comments

Comments
 (0)