Skip to content

Commit 2b5227c

Browse files
bors[bot]cuviper
andcommitted
665: Add ParallelIterator::copied() r=nikomatsakis a=cuviper Co-authored-by: Josh Stone <cuviper@gmail.com>
2 parents b8b97a1 + 0d17931 commit 2b5227c

File tree

6 files changed

+273
-2
lines changed

6 files changed

+273
-2
lines changed

src/compile_fail/must_use.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ must_use! {
3333
chain /** v.par_iter().chain(&v); */
3434
chunks /** v.par_iter().chunks(2); */
3535
cloned /** v.par_iter().cloned(); */
36+
copied /** v.par_iter().copied(); */
3637
enumerate /** v.par_iter().enumerate(); */
3738
filter /** v.par_iter().filter(|_| true); */
3839
filter_map /** v.par_iter().filter_map(|x| *x); */

src/iter/copied.rs

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
use super::plumbing::*;
2+
use super::*;
3+
4+
use std::iter;
5+
6+
/// `Copied` is an iterator that copies the elements of an underlying iterator.
7+
///
8+
/// This struct is created by the [`copied()`] method on [`ParallelIterator`]
9+
///
10+
/// [`copied()`]: trait.ParallelIterator.html#method.copied
11+
/// [`ParallelIterator`]: trait.ParallelIterator.html
12+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
13+
#[derive(Debug, Clone)]
14+
pub struct Copied<I: ParallelIterator> {
15+
base: I,
16+
}
17+
18+
impl<I> Copied<I>
19+
where
20+
I: ParallelIterator,
21+
{
22+
/// Create a new `Copied` iterator.
23+
pub(super) fn new(base: I) -> Self {
24+
Copied { base }
25+
}
26+
}
27+
28+
impl<'a, T, I> ParallelIterator for Copied<I>
29+
where
30+
I: ParallelIterator<Item = &'a T>,
31+
T: 'a + Copy + Send + Sync,
32+
{
33+
type Item = T;
34+
35+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
36+
where
37+
C: UnindexedConsumer<Self::Item>,
38+
{
39+
let consumer1 = CopiedConsumer::new(consumer);
40+
self.base.drive_unindexed(consumer1)
41+
}
42+
43+
fn opt_len(&self) -> Option<usize> {
44+
self.base.opt_len()
45+
}
46+
}
47+
48+
impl<'a, T, I> IndexedParallelIterator for Copied<I>
49+
where
50+
I: IndexedParallelIterator<Item = &'a T>,
51+
T: 'a + Copy + Send + Sync,
52+
{
53+
fn drive<C>(self, consumer: C) -> C::Result
54+
where
55+
C: Consumer<Self::Item>,
56+
{
57+
let consumer1 = CopiedConsumer::new(consumer);
58+
self.base.drive(consumer1)
59+
}
60+
61+
fn len(&self) -> usize {
62+
self.base.len()
63+
}
64+
65+
fn with_producer<CB>(self, callback: CB) -> CB::Output
66+
where
67+
CB: ProducerCallback<Self::Item>,
68+
{
69+
return self.base.with_producer(Callback { callback });
70+
71+
struct Callback<CB> {
72+
callback: CB,
73+
}
74+
75+
impl<'a, T, CB> ProducerCallback<&'a T> for Callback<CB>
76+
where
77+
CB: ProducerCallback<T>,
78+
T: 'a + Copy + Send,
79+
{
80+
type Output = CB::Output;
81+
82+
fn callback<P>(self, base: P) -> CB::Output
83+
where
84+
P: Producer<Item = &'a T>,
85+
{
86+
let producer = CopiedProducer { base };
87+
self.callback.callback(producer)
88+
}
89+
}
90+
}
91+
}
92+
93+
/// ////////////////////////////////////////////////////////////////////////
94+
95+
struct CopiedProducer<P> {
96+
base: P,
97+
}
98+
99+
impl<'a, T, P> Producer for CopiedProducer<P>
100+
where
101+
P: Producer<Item = &'a T>,
102+
T: 'a + Copy,
103+
{
104+
type Item = T;
105+
type IntoIter = iter::Map<P::IntoIter, fn(&T) -> T>;
106+
107+
fn into_iter(self) -> Self::IntoIter {
108+
// FIXME: use `Iterator::copied()` when Rust 1.36 is our minimum.
109+
self.base.into_iter().map(|&x| x)
110+
}
111+
112+
fn min_len(&self) -> usize {
113+
self.base.min_len()
114+
}
115+
116+
fn max_len(&self) -> usize {
117+
self.base.max_len()
118+
}
119+
120+
fn split_at(self, index: usize) -> (Self, Self) {
121+
let (left, right) = self.base.split_at(index);
122+
(
123+
CopiedProducer { base: left },
124+
CopiedProducer { base: right },
125+
)
126+
}
127+
128+
fn fold_with<F>(self, folder: F) -> F
129+
where
130+
F: Folder<Self::Item>,
131+
{
132+
self.base.fold_with(CopiedFolder { base: folder }).base
133+
}
134+
}
135+
136+
/// ////////////////////////////////////////////////////////////////////////
137+
/// Consumer implementation
138+
139+
struct CopiedConsumer<C> {
140+
base: C,
141+
}
142+
143+
impl<C> CopiedConsumer<C> {
144+
fn new(base: C) -> Self {
145+
CopiedConsumer { base }
146+
}
147+
}
148+
149+
impl<'a, T, C> Consumer<&'a T> for CopiedConsumer<C>
150+
where
151+
C: Consumer<T>,
152+
T: 'a + Copy,
153+
{
154+
type Folder = CopiedFolder<C::Folder>;
155+
type Reducer = C::Reducer;
156+
type Result = C::Result;
157+
158+
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
159+
let (left, right, reducer) = self.base.split_at(index);
160+
(
161+
CopiedConsumer::new(left),
162+
CopiedConsumer::new(right),
163+
reducer,
164+
)
165+
}
166+
167+
fn into_folder(self) -> Self::Folder {
168+
CopiedFolder {
169+
base: self.base.into_folder(),
170+
}
171+
}
172+
173+
fn full(&self) -> bool {
174+
self.base.full()
175+
}
176+
}
177+
178+
impl<'a, T, C> UnindexedConsumer<&'a T> for CopiedConsumer<C>
179+
where
180+
C: UnindexedConsumer<T>,
181+
T: 'a + Copy,
182+
{
183+
fn split_off_left(&self) -> Self {
184+
CopiedConsumer::new(self.base.split_off_left())
185+
}
186+
187+
fn to_reducer(&self) -> Self::Reducer {
188+
self.base.to_reducer()
189+
}
190+
}
191+
192+
struct CopiedFolder<F> {
193+
base: F,
194+
}
195+
196+
impl<'a, T, F> Folder<&'a T> for CopiedFolder<F>
197+
where
198+
F: Folder<T>,
199+
T: 'a + Copy,
200+
{
201+
type Result = F::Result;
202+
203+
fn consume(self, &item: &'a T) -> Self {
204+
CopiedFolder {
205+
base: self.base.consume(item),
206+
}
207+
}
208+
209+
fn consume_iter<I>(mut self, iter: I) -> Self
210+
where
211+
I: IntoIterator<Item = &'a T>,
212+
{
213+
// FIXME: use `Iterator::copied()` when Rust 1.36 is our minimum.
214+
self.base = self.base.consume_iter(iter.into_iter().map(|&x| x));
215+
self
216+
}
217+
218+
fn complete(self) -> F::Result {
219+
self.base.complete()
220+
}
221+
222+
fn full(&self) -> bool {
223+
self.base.full()
224+
}
225+
}

src/iter/mod.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,15 @@ mod rev;
149149
pub use self::rev::Rev;
150150
mod len;
151151
pub use self::len::{MaxLen, MinLen};
152+
152153
mod cloned;
154+
pub use self::cloned::Cloned;
155+
mod copied;
156+
pub use self::copied::Copied;
157+
153158
mod product;
154159
mod sum;
155-
pub use self::cloned::Cloned;
160+
156161
mod inspect;
157162
pub use self::inspect::Inspect;
158163
mod panic_fuse;
@@ -640,7 +645,10 @@ pub trait ParallelIterator: Sized + Send {
640645
}
641646

642647
/// Creates an iterator which clones all of its elements. This may be
643-
/// useful when you have an iterator over `&T`, but you need `T`.
648+
/// useful when you have an iterator over `&T`, but you need `T`, and
649+
/// that type implements `Clone`. See also [`copied()`].
650+
///
651+
/// [`copied()`]: #method.copied
644652
///
645653
/// # Examples
646654
///
@@ -665,6 +673,35 @@ pub trait ParallelIterator: Sized + Send {
665673
Cloned::new(self)
666674
}
667675

676+
/// Creates an iterator which copies all of its elements. This may be
677+
/// useful when you have an iterator over `&T`, but you need `T`, and
678+
/// that type implements `Copy`. See also [`cloned()`].
679+
///
680+
/// [`cloned()`]: #method.cloned
681+
///
682+
/// # Examples
683+
///
684+
/// ```
685+
/// use rayon::prelude::*;
686+
///
687+
/// let a = [1, 2, 3];
688+
///
689+
/// let v_copied: Vec<_> = a.par_iter().copied().collect();
690+
///
691+
/// // copied is the same as .map(|&x| x), for integers
692+
/// let v_map: Vec<_> = a.par_iter().map(|&x| x).collect();
693+
///
694+
/// assert_eq!(v_copied, vec![1, 2, 3]);
695+
/// assert_eq!(v_map, vec![1, 2, 3]);
696+
/// ```
697+
fn copied<'a, T>(self) -> Copied<Self>
698+
where
699+
T: 'a + Copy + Send,
700+
Self: ParallelIterator<Item = &'a T>,
701+
{
702+
Copied::new(self)
703+
}
704+
668705
/// Applies `inspect_op` to a reference to each item of this iterator,
669706
/// producing a new iterator passing through the original items. This is
670707
/// often useful for debugging to see what's happening in iterator stages.

tests/clones.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ fn clone_adaptors() {
113113
let v: Vec<_> = (0..1000).map(Some).collect();
114114
check(v.par_iter().chain(&v));
115115
check(v.par_iter().cloned());
116+
check(v.par_iter().copied());
116117
check(v.par_iter().enumerate());
117118
check(v.par_iter().filter(|_| true));
118119
check(v.par_iter().filter_map(|x| *x));

tests/debug.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ fn debug_adaptors() {
124124
let v: Vec<_> = (0..10).collect();
125125
check(v.par_iter().chain(&v));
126126
check(v.par_iter().cloned());
127+
check(v.par_iter().copied());
127128
check(v.par_iter().enumerate());
128129
check(v.par_iter().filter(|_| true));
129130
check(v.par_iter().filter_map(Some));

tests/producer_split_at.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ fn cloned() {
214214
check(&v, || v.par_iter().cloned());
215215
}
216216

217+
#[test]
218+
fn copied() {
219+
let v: Vec<_> = (0..10).collect();
220+
check(&v, || v.par_iter().copied());
221+
}
222+
217223
#[test]
218224
fn enumerate() {
219225
let v: Vec<_> = (0..10).enumerate().collect();

0 commit comments

Comments
 (0)