Skip to content

Commit eceb102

Browse files
bors[bot]cuviper
andcommitted
602: Add ParallelIterator::{map_init,for_each_init,try_for_each_init} r=nikomatsakis a=cuviper These are like `map_with` and all, except using an `init` function for the paired value instead of a `Send + Clone` value. The returned type doesn't have to be `Send` nor `Sync` nor anything else, which makes it feasible for things like a thread-local RNG. Co-authored-by: Josh Stone <[email protected]>
2 parents 217cf05 + 5312769 commit eceb102

File tree

6 files changed

+374
-5
lines changed

6 files changed

+374
-5
lines changed

src/compile_fail/must_use.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@
44

55
macro_rules! must_use {
66
($( $name:ident #[$expr:meta] )*) => {$(
7+
/// First sanity check that the expression is OK.
8+
///
9+
/// ```
10+
/// #![deny(unused_must_use)]
11+
///
12+
/// use rayon::prelude::*;
13+
///
14+
/// let v: Vec<_> = (0..100).map(Some).collect();
15+
/// let _ =
16+
#[$expr]
17+
/// ```
18+
///
19+
/// Now trigger the `must_use`.
20+
///
721
/// ```compile_fail
822
/// #![deny(unused_must_use)]
923
///
@@ -35,6 +49,7 @@ must_use! {
3549
intersperse /** v.par_iter().intersperse(&None); */
3650
map /** v.par_iter().map(|x| x); */
3751
map_with /** v.par_iter().map_with(0, |_, x| x); */
52+
map_init /** v.par_iter().map_init(|| 0, |_, x| x); */
3853
rev /** v.par_iter().rev(); */
3954
skip /** v.par_iter().skip(1); */
4055
take /** v.par_iter().take(1); */

src/iter/map_with.rs

Lines changed: 234 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ struct MapWithIter<'f, I, U, F: 'f> {
180180

181181
impl<'f, I, U, F, R> Iterator for MapWithIter<'f, I, U, F>
182182
where I: Iterator,
183-
U: Send + Clone,
184183
F: Fn(&mut U, I::Item) -> R + Sync,
185184
R: Send
186185
{
@@ -197,7 +196,6 @@ impl<'f, I, U, F, R> Iterator for MapWithIter<'f, I, U, F>
197196

198197
impl<'f, I, U, F, R> DoubleEndedIterator for MapWithIter<'f, I, U, F>
199198
where I: DoubleEndedIterator,
200-
U: Send + Clone,
201199
F: Fn(&mut U, I::Item) -> R + Sync,
202200
R: Send
203201
{
@@ -208,7 +206,6 @@ impl<'f, I, U, F, R> DoubleEndedIterator for MapWithIter<'f, I, U, F>
208206

209207
impl<'f, I, U, F, R> ExactSizeIterator for MapWithIter<'f, I, U, F>
210208
where I: ExactSizeIterator,
211-
U: Send + Clone,
212209
F: Fn(&mut U, I::Item) -> R + Sync,
213210
R: Send
214211
{
@@ -287,7 +284,6 @@ struct MapWithFolder<'f, C, U, F: 'f> {
287284

288285
impl<'f, T, U, R, C, F> Folder<T> for MapWithFolder<'f, C, U, F>
289286
where C: Folder<R>,
290-
U: Clone,
291287
F: Fn(&mut U, T) -> R
292288
{
293289
type Result = C::Result;
@@ -318,3 +314,237 @@ impl<'f, T, U, R, C, F> Folder<T> for MapWithFolder<'f, C, U, F>
318314
self.base.full()
319315
}
320316
}
317+
318+
// ------------------------------------------------------------------------------------------------
319+
320+
/// `MapInit` is an iterator that transforms the elements of an underlying iterator.
321+
///
322+
/// This struct is created by the [`map_init()`] method on [`ParallelIterator`]
323+
///
324+
/// [`map_init()`]: trait.ParallelIterator.html#method.map_init
325+
/// [`ParallelIterator`]: trait.ParallelIterator.html
326+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
327+
#[derive(Clone)]
328+
pub struct MapInit<I: ParallelIterator, INIT, F> {
329+
base: I,
330+
init: INIT,
331+
map_op: F,
332+
}
333+
334+
impl<I: ParallelIterator + Debug, INIT, F> Debug for MapInit<I, INIT, F> {
335+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336+
f.debug_struct("MapInit")
337+
.field("base", &self.base)
338+
.finish()
339+
}
340+
}
341+
342+
/// Create a new `MapInit` iterator.
343+
///
344+
/// NB: a free fn because it is NOT part of the end-user API.
345+
pub fn new_init<I, INIT, F>(base: I, init: INIT, map_op: F) -> MapInit<I, INIT, F>
346+
where I: ParallelIterator
347+
{
348+
MapInit {
349+
base: base,
350+
init: init,
351+
map_op: map_op,
352+
}
353+
}
354+
355+
impl<I, INIT, T, F, R> ParallelIterator for MapInit<I, INIT, F>
356+
where I: ParallelIterator,
357+
INIT: Fn() -> T + Sync + Send,
358+
F: Fn(&mut T, I::Item) -> R + Sync + Send,
359+
R: Send
360+
{
361+
type Item = R;
362+
363+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
364+
where C: UnindexedConsumer<Self::Item>
365+
{
366+
let consumer1 = MapInitConsumer::new(consumer, &self.init, &self.map_op);
367+
self.base.drive_unindexed(consumer1)
368+
}
369+
370+
fn opt_len(&self) -> Option<usize> {
371+
self.base.opt_len()
372+
}
373+
}
374+
375+
impl<I, INIT, T, F, R> IndexedParallelIterator for MapInit<I, INIT, F>
376+
where I: IndexedParallelIterator,
377+
INIT: Fn() -> T + Sync + Send,
378+
F: Fn(&mut T, I::Item) -> R + Sync + Send,
379+
R: Send
380+
{
381+
fn drive<C>(self, consumer: C) -> C::Result
382+
where C: Consumer<Self::Item>
383+
{
384+
let consumer1 = MapInitConsumer::new(consumer, &self.init, &self.map_op);
385+
self.base.drive(consumer1)
386+
}
387+
388+
fn len(&self) -> usize {
389+
self.base.len()
390+
}
391+
392+
fn with_producer<CB>(self, callback: CB) -> CB::Output
393+
where CB: ProducerCallback<Self::Item>
394+
{
395+
return self.base.with_producer(Callback {
396+
callback: callback,
397+
init: self.init,
398+
map_op: self.map_op,
399+
});
400+
401+
struct Callback<CB, INIT, F> {
402+
callback: CB,
403+
init: INIT,
404+
map_op: F,
405+
}
406+
407+
impl<T, INIT, U, F, R, CB> ProducerCallback<T> for Callback<CB, INIT, F>
408+
where CB: ProducerCallback<R>,
409+
INIT: Fn() -> U + Sync,
410+
F: Fn(&mut U, T) -> R + Sync,
411+
R: Send
412+
{
413+
type Output = CB::Output;
414+
415+
fn callback<P>(self, base: P) -> CB::Output
416+
where P: Producer<Item = T>
417+
{
418+
let producer = MapInitProducer {
419+
base: base,
420+
init: &self.init,
421+
map_op: &self.map_op,
422+
};
423+
self.callback.callback(producer)
424+
}
425+
}
426+
}
427+
}
428+
429+
/// ////////////////////////////////////////////////////////////////////////
430+
431+
struct MapInitProducer<'f, P, INIT: 'f, F: 'f> {
432+
base: P,
433+
init: &'f INIT,
434+
map_op: &'f F,
435+
}
436+
437+
impl<'f, P, INIT, U, F, R> Producer for MapInitProducer<'f, P, INIT, F>
438+
where P: Producer,
439+
INIT: Fn() -> U + Sync,
440+
F: Fn(&mut U, P::Item) -> R + Sync,
441+
R: Send
442+
{
443+
type Item = R;
444+
type IntoIter = MapWithIter<'f, P::IntoIter, U, F>;
445+
446+
fn into_iter(self) -> Self::IntoIter {
447+
MapWithIter {
448+
base: self.base.into_iter(),
449+
item: (self.init)(),
450+
map_op: self.map_op,
451+
}
452+
}
453+
454+
fn min_len(&self) -> usize {
455+
self.base.min_len()
456+
}
457+
fn max_len(&self) -> usize {
458+
self.base.max_len()
459+
}
460+
461+
fn split_at(self, index: usize) -> (Self, Self) {
462+
let (left, right) = self.base.split_at(index);
463+
(MapInitProducer {
464+
base: left,
465+
init: self.init,
466+
map_op: self.map_op,
467+
},
468+
MapInitProducer {
469+
base: right,
470+
init: self.init,
471+
map_op: self.map_op,
472+
})
473+
}
474+
475+
fn fold_with<G>(self, folder: G) -> G
476+
where G: Folder<Self::Item>
477+
{
478+
let folder1 = MapWithFolder {
479+
base: folder,
480+
item: (self.init)(),
481+
map_op: self.map_op,
482+
};
483+
self.base.fold_with(folder1).base
484+
}
485+
}
486+
487+
488+
/// ////////////////////////////////////////////////////////////////////////
489+
/// Consumer implementation
490+
491+
struct MapInitConsumer<'f, C, INIT: 'f, F: 'f> {
492+
base: C,
493+
init: &'f INIT,
494+
map_op: &'f F,
495+
}
496+
497+
impl<'f, C, INIT, F> MapInitConsumer<'f, C, INIT, F> {
498+
fn new(base: C, init: &'f INIT, map_op: &'f F) -> Self {
499+
MapInitConsumer {
500+
base: base,
501+
init: init,
502+
map_op: map_op,
503+
}
504+
}
505+
}
506+
507+
impl<'f, T, INIT, U, R, C, F> Consumer<T> for MapInitConsumer<'f, C, INIT, F>
508+
where C: Consumer<R>,
509+
INIT: Fn() -> U + Sync,
510+
F: Fn(&mut U, T) -> R + Sync,
511+
R: Send
512+
{
513+
type Folder = MapWithFolder<'f, C::Folder, U, F>;
514+
type Reducer = C::Reducer;
515+
type Result = C::Result;
516+
517+
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
518+
let (left, right, reducer) = self.base.split_at(index);
519+
(MapInitConsumer::new(left, self.init, self.map_op),
520+
MapInitConsumer::new(right, self.init, self.map_op),
521+
reducer)
522+
}
523+
524+
fn into_folder(self) -> Self::Folder {
525+
MapWithFolder {
526+
base: self.base.into_folder(),
527+
item: (self.init)(),
528+
map_op: self.map_op,
529+
}
530+
}
531+
532+
fn full(&self) -> bool {
533+
self.base.full()
534+
}
535+
}
536+
537+
impl<'f, T, INIT, U, R, C, F> UnindexedConsumer<T> for MapInitConsumer<'f, C, INIT, F>
538+
where C: UnindexedConsumer<R>,
539+
INIT: Fn() -> U + Sync,
540+
F: Fn(&mut U, T) -> R + Sync,
541+
R: Send
542+
{
543+
fn split_off_left(&self) -> Self {
544+
MapInitConsumer::new(self.base.split_off_left(), self.init, self.map_op)
545+
}
546+
547+
fn to_reducer(&self) -> Self::Reducer {
548+
self.base.to_reducer()
549+
}
550+
}

0 commit comments

Comments
 (0)