1use crate::iter::FusedIterator;
2use crate::mem::MaybeUninit;
3use crate::{fmt, ptr};
45/// An iterator over the mapped windows of another iterator.
6///
7/// This `struct` is created by the [`Iterator::map_windows`]. See its
8/// documentation for more information.
9#[must_use = "iterators are lazy and do nothing unless consumed"]
10#[unstable(feature = "iter_map_windows", issue = "87155")]
11pub struct MapWindows<I: Iterator, F, const N: usize> {
12 f: F,
13 inner: MapWindowsInner<I, N>,
14}
1516struct MapWindowsInner<I: Iterator, const N: usize> {
17 iter: I,
18// Since iterators are assumed lazy, i.e. it only yields an item when
19 // `Iterator::next()` is called, and `MapWindows` is not an exception.
20 //
21 // Before the first iteration, we keep the buffer `None`. When the user
22 // first call `next` or other methods that makes the iterator advance,
23 // we collect the first `N` items yielded from the inner iterator and
24 // put it into the buffer.
25 //
26 // When the inner iterator has returned a `None`, we take
27 // away this `buffer` and leave it `None` to reclaim its resources.
28 //
29 // FIXME: should we shrink the size of `buffer` using niche optimization?
30buffer: Option<Buffer<I::Item, N>>,
31}
3233// `Buffer` uses two times of space to reduce moves among the iterations.
34// `Buffer<T, N>` is semantically `[MaybeUninit<T>; 2 * N]`. However, due
35// to limitations of const generics, we use this different type. Note that
36// it has the same underlying memory layout.
37struct Buffer<T, const N: usize> {
38// Invariant: `self.buffer[self.start..self.start + N]` is initialized,
39 // with all other elements being uninitialized. This also
40 // implies that `self.start <= N`.
41buffer: [[MaybeUninit<T>; N]; 2],
42 start: usize,
43}
4445impl<I: Iterator, F, const N: usize> MapWindows<I, F, N> {
46pub(in crate::iter) const fn new(iter: I, f: F) -> Self {
47if !(N != 0) {
{
crate::panicking::panic_fmt(format_args!("array in `Iterator::map_windows` must contain more than 0 elements"));
}
};assert!(N != 0, "array in `Iterator::map_windows` must contain more than 0 elements");
4849// Only ZST arrays' length can be so large.
50if size_of::<I::Item>() == 0 {
51if !N.checked_mul(2).is_some() {
{
crate::panicking::panic_fmt(format_args!("array size of `Iterator::map_windows` is too large"));
}
};assert!(
52 N.checked_mul(2).is_some(),
53"array size of `Iterator::map_windows` is too large"
54);
55 }
5657Self { inner: MapWindowsInner::new(iter), f }
58 }
59}
6061impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
62#[inline]
63const fn new(iter: I) -> Self {
64Self { iter, buffer: None }
65 }
6667fn next_window(&mut self) -> Option<&[I::Item; N]> {
68match self.buffer {
69// It is the first time to advance. We collect
70 // the first `N` items from `self.iter` to initialize `self.buffer`.
71None => self.buffer = Buffer::try_from_iter(&mut self.iter),
72Some(ref mut buffer) => match self.iter.next() {
73None => {
74self.buffer.take();
75 }
76// Advance the iterator. We first call `next` before changing our buffer
77 // at all. This means that if `next` panics, our invariant is upheld and
78 // our `Drop` impl drops the correct elements.
79Some(item) => buffer.push(item),
80 },
81 }
82self.buffer.as_ref().map(Buffer::as_array_ref)
83 }
8485fn size_hint(&self) -> (usize, Option<usize>) {
86let (lo, hi) = self.iter.size_hint();
87if self.buffer.is_some() {
88// If the first `N` items are already yielded by the inner iterator,
89 // the size hint is then equal to the that of the inner iterator's.
90(lo, hi)
91 } else {
92// If the first `N` items are not yet yielded by the inner iterator,
93 // the first `N` elements should be counted as one window, so both bounds
94 // should subtract `N - 1`.
95(lo.saturating_sub(N - 1), hi.map(|hi| hi.saturating_sub(N - 1)))
96 }
97 }
98}
99100impl<T, const N: usize> Buffer<T, N> {
101fn try_from_iter(iter: &mut impl Iterator<Item = T>) -> Option<Self> {
102let first_half = crate::array::iter_next_chunk(iter).ok()?;
103let buffer =
104 [MaybeUninit::new(first_half).transpose(), [const { MaybeUninit::uninit() }; N]];
105Some(Self { buffer, start: 0 })
106 }
107108#[inline]
109fn buffer_ptr(&self) -> *const MaybeUninit<T> {
110self.buffer.as_ptr().cast()
111 }
112113#[inline]
114fn buffer_mut_ptr(&mut self) -> *mut MaybeUninit<T> {
115self.buffer.as_mut_ptr().cast()
116 }
117118#[inline]
119fn as_array_ref(&self) -> &[T; N] {
120if true {
if !(self.start + N <= 2 * N) {
crate::panicking::panic("assertion failed: self.start + N <= 2 * N")
};
};debug_assert!(self.start + N <= 2 * N);
121122// SAFETY: our invariant guarantees these elements are initialized.
123unsafe { &*self.buffer_ptr().add(self.start).cast() }
124 }
125126#[inline]
127fn as_uninit_array_mut(&mut self) -> &mut MaybeUninit<[T; N]> {
128if true {
if !(self.start + N <= 2 * N) {
crate::panicking::panic("assertion failed: self.start + N <= 2 * N")
};
};debug_assert!(self.start + N <= 2 * N);
129130// SAFETY: our invariant guarantees these elements are in bounds.
131unsafe { &mut *self.buffer_mut_ptr().add(self.start).cast() }
132 }
133134/// Pushes a new item `next` to the back, and pops the front-most one.
135 ///
136 /// All the elements will be shifted to the front end when pushing reaches
137 /// the back end.
138fn push(&mut self, next: T) {
139let buffer_mut_ptr = self.buffer_mut_ptr();
140if true {
if !(self.start + N <= 2 * N) {
crate::panicking::panic("assertion failed: self.start + N <= 2 * N")
};
};debug_assert!(self.start + N <= 2 * N);
141142let to_drop = if self.start == N {
143// We have reached the end of our buffer and have to copy
144 // everything to the start. Example layout for N = 3.
145 //
146 // 0 1 2 3 4 5 0 1 2 3 4 5
147 // ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┐
148 // │ - │ - │ - │ a │ b │ c │ -> │ b │ c │ n │ - │ - │ - │
149 // └───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┘
150 // ↑ ↑
151 // start start
152153 // SAFETY: the two pointers are valid for reads/writes of N -1
154 // elements because our array's size is semantically 2 * N. The
155 // regions also don't overlap for the same reason.
156 //
157 // We leave the old elements in place. As soon as `start` is set
158 // to 0, we treat them as uninitialized and treat their copies
159 // as initialized.
160let to_drop = unsafe {
161 ptr::copy_nonoverlapping(buffer_mut_ptr.add(self.start + 1), buffer_mut_ptr, N - 1);
162 (*buffer_mut_ptr.add(N - 1)).write(next);
163buffer_mut_ptr.add(self.start)
164 };
165self.start = 0;
166to_drop167 } else {
168// SAFETY: `self.start` is < N as guaranteed by the invariant
169 // plus the check above. Even if the drop at the end panics,
170 // the invariant is upheld.
171 //
172 // Example layout for N = 3:
173 //
174 // 0 1 2 3 4 5 0 1 2 3 4 5
175 // ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┐
176 // │ - │ a │ b │ c │ - │ - │ -> │ - │ - │ b │ c │ n │ - │
177 // └───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┘
178 // ↑ ↑
179 // start start
180 //
181let to_drop = unsafe {
182 (*buffer_mut_ptr.add(self.start + N)).write(next);
183buffer_mut_ptr.add(self.start)
184 };
185self.start += 1;
186to_drop187 };
188189// SAFETY: the index is valid and this is element `a` in the
190 // diagram above and has not been dropped yet.
191unsafe { ptr::drop_in_place(to_drop.cast_init()) };
192 }
193}
194195impl<T: Clone, const N: usize> Clonefor Buffer<T, N> {
196fn clone(&self) -> Self {
197let mut buffer = Buffer {
198 buffer: [[const { MaybeUninit::uninit() }; N], [const { MaybeUninit::uninit() }; N]],
199 start: self.start,
200 };
201buffer.as_uninit_array_mut().write(self.as_array_ref().clone());
202buffer203 }
204}
205206impl<I, const N: usize> Clonefor MapWindowsInner<I, N>
207where
208I: Iterator + Clone,
209 I::Item: Clone,
210{
211fn clone(&self) -> Self {
212Self { iter: self.iter.clone(), buffer: self.buffer.clone() }
213 }
214}
215216impl<T, const N: usize> Dropfor Buffer<T, N> {
217fn drop(&mut self) {
218// SAFETY: our invariant guarantees that N elements starting from
219 // `self.start` are initialized. We drop them here.
220unsafe {
221let initialized_part: *mut [T] = crate::ptr::slice_from_raw_parts_mut(
222self.buffer_mut_ptr().add(self.start).cast(),
223N,
224 );
225 ptr::drop_in_place(initialized_part);
226 }
227 }
228}
229230#[unstable(feature = "iter_map_windows", issue = "87155")]
231impl<I, F, R, const N: usize> Iteratorfor MapWindows<I, F, N>
232where
233I: Iterator,
234 F: FnMut(&[I::Item; N]) -> R,
235{
236type Item = R;
237238fn next(&mut self) -> Option<Self::Item> {
239let window = self.inner.next_window()?;
240let out = (self.f)(window);
241Some(out)
242 }
243244fn size_hint(&self) -> (usize, Option<usize>) {
245self.inner.size_hint()
246 }
247}
248249#[unstable(feature = "iter_map_windows", issue = "87155")]
250impl<I, F, R, const N: usize> FusedIteratorfor MapWindows<I, F, N>
251where
252I: FusedIterator,
253 F: FnMut(&[I::Item; N]) -> R,
254{
255}
256257#[unstable(feature = "iter_map_windows", issue = "87155")]
258impl<I, F, R, const N: usize> ExactSizeIteratorfor MapWindows<I, F, N>
259where
260I: ExactSizeIterator,
261 F: FnMut(&[I::Item; N]) -> R,
262{
263}
264265#[unstable(feature = "iter_map_windows", issue = "87155")]
266impl<I: Iterator + fmt::Debug, F, const N: usize> fmt::Debugfor MapWindows<I, F, N> {
267fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268f.debug_struct("MapWindows").field("iter", &self.inner.iter).finish()
269 }
270}
271272#[unstable(feature = "iter_map_windows", issue = "87155")]
273impl<I, F, const N: usize> Clonefor MapWindows<I, F, N>
274where
275I: Iterator + Clone,
276 F: Clone,
277 I::Item: Clone,
278{
279fn clone(&self) -> Self {
280Self { f: self.f.clone(), inner: self.inner.clone() }
281 }
282}