Skip to content

Commit 9a72782

Browse files
committed
Add const-generic par_array_windows
1 parent 12d4f24 commit 9a72782

File tree

5 files changed

+91
-3
lines changed

5 files changed

+91
-3
lines changed

src/slice/array.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::iter::plumbing::*;
22
use crate::iter::*;
33

4-
use super::{Iter, IterMut};
4+
use super::{Iter, IterMut, ParallelSlice};
55

66
/// Parallel iterator over immutable non-overlapping chunks of a slice
77
#[derive(Debug)]
@@ -170,3 +170,67 @@ impl<'data, T: Send + 'data, const N: usize> IndexedParallelIterator
170170
self.iter.with_producer(callback)
171171
}
172172
}
173+
174+
/// Parallel iterator over immutable overlapping windows of a slice
175+
#[derive(Debug)]
176+
pub struct ArrayWindows<'data, T: Sync, const N: usize> {
177+
slice: &'data [T],
178+
}
179+
180+
impl<'data, T: Sync, const N: usize> ArrayWindows<'data, T, N> {
181+
pub(super) fn new(slice: &'data [T]) -> Self {
182+
ArrayWindows { slice }
183+
}
184+
}
185+
186+
impl<'data, T: Sync, const N: usize> Clone for ArrayWindows<'data, T, N> {
187+
fn clone(&self) -> Self {
188+
ArrayWindows { ..*self }
189+
}
190+
}
191+
192+
impl<'data, T: Sync + 'data, const N: usize> ParallelIterator for ArrayWindows<'data, T, N> {
193+
type Item = &'data [T; N];
194+
195+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
196+
where
197+
C: UnindexedConsumer<Self::Item>,
198+
{
199+
bridge(self, consumer)
200+
}
201+
202+
fn opt_len(&self) -> Option<usize> {
203+
Some(self.len())
204+
}
205+
}
206+
207+
impl<'data, T: Sync + 'data, const N: usize> IndexedParallelIterator for ArrayWindows<'data, T, N> {
208+
fn drive<C>(self, consumer: C) -> C::Result
209+
where
210+
C: Consumer<Self::Item>,
211+
{
212+
bridge(self, consumer)
213+
}
214+
215+
fn len(&self) -> usize {
216+
assert!(N >= 1);
217+
self.slice.len().saturating_sub(N - 1)
218+
}
219+
220+
fn with_producer<CB>(self, callback: CB) -> CB::Output
221+
where
222+
CB: ProducerCallback<Self::Item>,
223+
{
224+
fn array<T, const N: usize>(slice: &[T]) -> &[T; N] {
225+
debug_assert_eq!(slice.len(), N);
226+
let ptr = slice.as_ptr() as *const [T; N];
227+
unsafe { &*ptr }
228+
}
229+
230+
// FIXME: use our own producer and the standard `array_windows`, rust-lang/rust#75027
231+
self.slice
232+
.par_windows(N)
233+
.map(array::<T, N>)
234+
.with_producer(callback)
235+
}
236+
}

src/slice/mod.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ mod rchunks;
1313

1414
mod test;
1515

16-
#[cfg(min_const_generics)]
17-
pub use self::array::{ArrayChunks, ArrayChunksMut};
16+
pub use self::array::{ArrayChunks, ArrayChunksMut, ArrayWindows};
1817

1918
use self::mergesort::par_mergesort;
2019
use self::quicksort::par_quicksort;
@@ -75,6 +74,20 @@ pub trait ParallelSlice<T: Sync> {
7574
}
7675
}
7776

77+
/// Returns a parallel iterator over all contiguous array windows of
78+
/// length `N`. The windows overlap.
79+
///
80+
/// # Examples
81+
///
82+
/// ```
83+
/// use rayon::prelude::*;
84+
/// let windows: Vec<_> = [1, 2, 3].par_array_windows().collect();
85+
/// assert_eq!(vec![&[1, 2], &[2, 3]], windows);
86+
/// ```
87+
fn par_array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
88+
ArrayWindows::new(self.as_parallel_slice())
89+
}
90+
7891
/// Returns a parallel iterator over at most `chunk_size` elements of
7992
/// `self` at a time. The chunks do not overlap.
8093
///

tests/clones.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ fn clone_vec() {
113113
check(v.par_rchunks_exact(42));
114114
check(v.par_array_chunks::<42>());
115115
check(v.par_windows(42));
116+
check(v.par_array_windows::<42>());
116117
check(v.par_split(|x| x % 3 == 0));
117118
check(v.into_par_iter());
118119
}

tests/debug.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ fn debug_vec() {
130130
check(v.par_rchunks_mut(42));
131131
check(v.par_rchunks_exact_mut(42));
132132
check(v.par_windows(42));
133+
check(v.par_array_windows::<42>());
133134
check(v.par_split(|x| x % 3 == 0));
134135
check(v.par_split_mut(|x| x % 3 == 0));
135136
check(v.par_drain(..));

tests/producer_split_at.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,15 @@ fn slice_windows() {
328328
check(&v, || s.par_windows(2));
329329
}
330330

331+
#[test]
332+
fn slice_array_windows() {
333+
use std::convert::TryInto;
334+
let s: Vec<_> = (0..10).collect();
335+
// FIXME: use the standard `array_windows`, rust-lang/rust#75027
336+
let v: Vec<&[_; 2]> = s.windows(2).map(|s| s.try_into().unwrap()).collect();
337+
check(&v, || s.par_array_windows::<2>());
338+
}
339+
331340
#[test]
332341
fn vec() {
333342
let v: Vec<_> = (0..10).collect();

0 commit comments

Comments
 (0)