Skip to content

Commit 218cb66

Browse files
committed
Add const-generic par_array_windows
1 parent 8eba0ef commit 218cb66

File tree

5 files changed

+92
-2
lines changed

5 files changed

+92
-2
lines changed

src/slice/array.rs

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

6-
use super::{Iter, IterMut};
6+
use super::{Iter, IterMut, ParallelSlice};
77

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

src/slice/mod.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod quicksort;
1212
mod test;
1313

1414
#[cfg(min_const_generics)]
15-
pub use self::array::{ArrayChunks, ArrayChunksMut};
15+
pub use self::array::{ArrayChunks, ArrayChunksMut, ArrayWindows};
1616

1717
use self::mergesort::par_mergesort;
1818
use self::quicksort::par_quicksort;
@@ -71,6 +71,21 @@ pub trait ParallelSlice<T: Sync> {
7171
}
7272
}
7373

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

tests/clones.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ fn clone_vec() {
104104
check(v.par_chunks_exact(42));
105105
check(v.par_array_chunks::<42>());
106106
check(v.par_windows(42));
107+
check(v.par_array_windows::<42>());
107108
check(v.par_split(|x| x % 3 == 0));
108109
check(v.into_par_iter());
109110
}

tests/debug.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ fn debug_vec() {
126126
check(v.par_chunks_exact_mut(42));
127127
check(v.par_array_chunks_mut::<42>());
128128
check(v.par_windows(42));
129+
check(v.par_array_windows::<42>());
129130
check(v.par_split(|x| x % 3 == 0));
130131
check(v.par_split_mut(|x| x % 3 == 0));
131132
check(v.par_drain(..));

tests/producer_split_at.rs

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

287+
#[test]
288+
fn slice_array_windows() {
289+
use std::convert::TryInto;
290+
let s: Vec<_> = (0..10).collect();
291+
// FIXME: use the standard `array_windows`, rust-lang/rust#75027
292+
let v: Vec<&[_; 2]> = s.windows(2).map(|s| s.try_into().unwrap()).collect();
293+
check(&v, || s.par_array_windows::<2>());
294+
}
295+
287296
#[test]
288297
fn vec() {
289298
let v: Vec<_> = (0..10).collect();

0 commit comments

Comments
 (0)