Skip to content

Commit

Permalink
Merge #627 #633
Browse files Browse the repository at this point in the history
627: Add `find_map` with `any`, `first`, and `last` variants r=cuviper a=seanchen1991

PR opened in response to #607. 

633: Update dev and demo dependencies r=cuviper a=cuviper

- `cgmath 0.17`
- `glium 0.23`
- `rand 0.6`

Co-authored-by: Sean <[email protected]>
Co-authored-by: Josh Stone <[email protected]>
  • Loading branch information
3 people committed Feb 19, 2019
3 parents 502c929 + 8fbb588 + d2609d8 commit abd942e
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ default-features = false
[dev-dependencies]
docopt = "1"
lazy_static = "1"
rand = "0.5"
rand = "0.6"
rand_xorshift = "0.1"
serde = "1"
serde_derive = "1"
3 changes: 2 additions & 1 deletion rayon-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ version = "0.2.0"
version = "0.3.0"

[dev-dependencies]
rand = "0.5"
rand = "0.6"
rand_xorshift = "0.1"

[[test]]
name = "stack_overflow_crash"
Expand Down
3 changes: 2 additions & 1 deletion rayon-core/src/join/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
use join::*;
use rand::distributions::Standard;
use rand::{Rng, SeedableRng, XorShiftRng};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use unwind;
use ThreadPoolBuilder;

Expand Down
2 changes: 2 additions & 0 deletions rayon-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ extern crate num_cpus;

#[cfg(test)]
extern crate rand;
#[cfg(test)]
extern crate rand_xorshift;

#[macro_use]
mod log;
Expand Down
3 changes: 2 additions & 1 deletion rayon-core/src/scope/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rand::{Rng, SeedableRng, XorShiftRng};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use std::cmp;
use std::iter::once;
use std::sync::atomic::{AtomicUsize, Ordering};
Expand Down
7 changes: 4 additions & 3 deletions rayon-demo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ publish = false

[dependencies]
rayon = { path = "../" }
cgmath = "0.16"
cgmath = "0.17"
docopt = "1"
fixedbitset = "0.1.5"
glium = "0.21"
glium = "0.23"
lazy_static = "1"
odds = "0.3"
rand = "0.5"
rand = "0.6"
rand_xorshift = "0.1"
regex = "1"
serde = "1"
serde_derive = "1"
Expand Down
6 changes: 4 additions & 2 deletions rayon-demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ extern crate libc; // life
extern crate num;
extern crate odds; // sieve
extern crate rand; // nbody
extern crate rand_xorshift; // nbody
extern crate time; // nbody, sieve // factorial
#[macro_use]
extern crate lazy_static; // find
Expand Down Expand Up @@ -109,8 +110,9 @@ fn main() {
}
}

fn seeded_rng() -> rand::XorShiftRng {
use rand::{SeedableRng, XorShiftRng};
fn seeded_rng() -> rand_xorshift::XorShiftRng {
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
let mut seed = <XorShiftRng as SeedableRng>::Seed::default();
(0..).zip(seed.as_mut()).for_each(|(i, x)| *x = i);
XorShiftRng::from_seed(seed)
Expand Down
4 changes: 2 additions & 2 deletions rayon-demo/src/nbody/visualize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ implement_vertex!(Instance, color, world_position);
pub fn visualize_benchmarks(num_bodies: usize, mut mode: ExecutionMode) {
let mut events_loop = EventsLoop::new();
let window = WindowBuilder::new()
.with_dimensions(800, 600)
.with_dimensions((800, 600).into())
.with_title("nbody demo".to_string());
let context = ContextBuilder::new().with_depth_buffer(24);
let display = Display::new(window, context, &events_loop).unwrap();
Expand Down Expand Up @@ -191,7 +191,7 @@ pub fn visualize_benchmarks(num_bodies: usize, mut mode: ExecutionMode) {
events_loop.poll_events(|event| {
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::Closed => done = true,
WindowEvent::CloseRequested => done = true,
WindowEvent::KeyboardInput { input, .. } => {
if let ElementState::Pressed = input.state {
match input.virtual_keycode {
Expand Down
4 changes: 2 additions & 2 deletions rayon-demo/src/str_split.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Some microbenchmarks for splitting strings
use rand::Rng;
use rand::seq::SliceRandom;
use rayon::prelude::*;
use test::Bencher;

lazy_static! {
static ref HAYSTACK: String = {
let mut rng = ::seeded_rng();
let mut bytes: Vec<u8> = "abcdefg ".bytes().cycle().take(1_000_000).collect();
rng.shuffle(&mut bytes);
bytes.shuffle(&mut rng);
String::from_utf8(bytes).unwrap()
};
static ref COUNT: usize = { HAYSTACK.split(' ').count() };
Expand Down
95 changes: 94 additions & 1 deletion src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ pub trait ParallelIterator: Sized + Send {
/// just want the first match that discovered anywhere in the iterator,
/// `find_any` is a better choice.
///
/// # Exmaples
/// # Examples
///
/// ```
/// use rayon::prelude::*;
Expand Down Expand Up @@ -1551,6 +1551,99 @@ pub trait ParallelIterator: Sized + Send {
find_first_last::find_last(self, predicate)
}

/// Applies the given predicate to the items in the parallel iterator
/// and returns **any** non-None result of the map operation.
///
/// Once a non-None value is produced from the map operation, we will
/// attempt to stop processing the rest of the items in the iterator
/// as soon as possible.
///
/// Note that this method only returns **some** item in the parallel
/// iterator that is not None from the map predicate. The item returned
/// may not be the **first** non-None value produced in the parallel
/// sequence, since the entire sequence is mapped over in parallel.
///
/// # Examples
///
/// ```
/// use rayon::prelude::*;
///
/// let c = ["lol", "NaN", "5", "5"];
///
/// let first_number = c.par_iter().find_map_first(|s| s.parse().ok());
///
/// assert_eq!(first_number, Some(5));
/// ```
fn find_map_any<P, R>(self, predicate: P) -> Option<R>
where
P: Fn(Self::Item) -> Option<R> + Sync + Send,
R: Send,
{
self.filter_map(predicate).find_any(|_| true)
}

/// Applies the given predicate to the items in the parallel iterator and
/// returns the sequentially **first** non-None result of the map operation.
///
/// Once a non-None value is produced from the map operation, all attempts
/// to the right of the match will be stopped, while attempts to the left
/// must continue in case an earlier match is found.
///
/// Note that not all parallel iterators have a useful order, much like
/// sequential `HashMap` iteration, so "first" may be nebulous. If you
/// just want the first non-None value discovered anywhere in the iterator,
/// `find_map_any` is a better choice.
///
/// # Examples
///
/// ```
/// use rayon::prelude::*;
///
/// let c = ["lol", "NaN", "2", "5"];
///
/// let first_number = c.par_iter().find_map_first(|s| s.parse().ok());
///
/// assert_eq!(first_number, Some(2));
/// ```
fn find_map_first<P, R>(self, predicate: P) -> Option<R>
where
P: Fn(Self::Item) -> Option<R> + Sync + Send,
R: Send,
{
self.filter_map(predicate).find_first(|_| true)
}

/// Applies the given predicate to the items in the parallel iterator and
/// returns the sequentially **last** non-None result of the map operation.
///
/// Once a non-None value is produced from the map operation, all attempts
/// to the left of the match will be stopped, while attempts to the right
/// must continue in case a later match is found.
///
/// Note that not all parallel iterators have a useful order, much like
/// sequential `HashMap` iteration, so "first" may be nebulous. If you
/// just want the first non-None value discovered anywhere in the iterator,
/// `find_map_any` is a better choice.
///
/// # Examples
///
/// ```
/// use rayon::prelude::*;
///
/// let c = ["lol", "NaN", "2", "5"];
///
/// let first_number = c.par_iter().find_map_last(|s| s.parse().ok());
///
/// assert_eq!(first_number, Some(5));
/// ```
fn find_map_last<P, R>(self, predicate: P) -> Option<R>
where
P: Fn(Self::Item) -> Option<R> + Sync + Send,
R: Send,
{
self.filter_map(predicate).find_last(|_| true)
}

#[doc(hidden)]
#[deprecated(note = "parallel `find` does not search in order -- use `find_any`, \\
`find_first`, or `find_last`")]
Expand Down
2 changes: 1 addition & 1 deletion src/iter/plumbing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ such as string characters.
## What on earth is `ProducerCallback`?

We saw that when you call a parallel action method like
`par_iter.reduce()`, that will creating a "reducing" consumer and then
`par_iter.reduce()`, that will create a "reducing" consumer and then
invoke `par_iter.drive_unindexed()` (or `par_iter.drive()`) as
appropriate. This may create yet more consumers as we proceed up the
parallel iterator chain. But at some point we're going to get to the
Expand Down
47 changes: 46 additions & 1 deletion src/iter/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use prelude::*;
use rayon_core::*;

use rand::distributions::Standard;
use rand::{Rng, SeedableRng, XorShiftRng};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use std::collections::LinkedList;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::collections::{BinaryHeap, VecDeque};
Expand Down Expand Up @@ -1271,6 +1272,50 @@ pub fn find_first_or_last() {
assert_eq!(a.par_iter().position_last(|&x| x < 0), None);
}

#[test]
pub fn find_map_first_or_last_or_any() {
let mut a: Vec<i32> = vec![];

assert!(a.par_iter().find_map_any(half_if_positive).is_none());
assert!(a.par_iter().find_map_first(half_if_positive).is_none());
assert!(a.par_iter().find_map_last(half_if_positive).is_none());

a = (-1024..-3).collect();

assert!(a.par_iter().find_map_any(half_if_positive).is_none());
assert!(a.par_iter().find_map_first(half_if_positive).is_none());
assert!(a.par_iter().find_map_last(half_if_positive).is_none());

assert!(a.par_iter().find_map_any(half_if_negative).is_some());
assert_eq!(
a.par_iter().find_map_first(half_if_negative),
Some(-512_i32)
);
assert_eq!(a.par_iter().find_map_last(half_if_negative), Some(-2_i32));

a.append(&mut (2..1025).collect());

assert!(a.par_iter().find_map_any(half_if_positive).is_some());
assert_eq!(a.par_iter().find_map_first(half_if_positive), Some(1_i32));
assert_eq!(a.par_iter().find_map_last(half_if_positive), Some(512_i32));

fn half_if_positive(x: &i32) -> Option<i32> {
if *x > 0 {
Some(x / 2)
} else {
None
}
}

fn half_if_negative(x: &i32) -> Option<i32> {
if *x < 0 {
Some(x / 2)
} else {
None
}
}
}

#[test]
pub fn check_find_not_present() {
let counter = AtomicUsize::new(0);
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ extern crate rayon_core;

#[cfg(test)]
extern crate rand;
#[cfg(test)]
extern crate rand_xorshift;

#[macro_use]
mod delegate;
Expand Down
6 changes: 3 additions & 3 deletions src/slice/mergesort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,9 +743,9 @@ mod tests {
let mut rng = thread_rng();

for _ in 0..100 {
let limit = rng.gen_range::<u32>(1, 21);
let left_len = rng.gen_range::<usize>(0, 20);
let right_len = rng.gen_range::<usize>(0, 20);
let limit: u32 = rng.gen_range(1, 21);
let left_len: usize = rng.gen_range(0, 20);
let right_len: usize = rng.gen_range(0, 20);

let mut left = rng
.sample_iter(&Uniform::new(0, limit))
Expand Down
6 changes: 4 additions & 2 deletions src/slice/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use super::ParallelSliceMut;
use rand::distributions::Uniform;
use rand::{thread_rng, Rng};
use rand::seq::SliceRandom;
use std::cmp::Ordering::{Equal, Greater, Less};

macro_rules! sort {
Expand Down Expand Up @@ -69,7 +70,7 @@ macro_rules! sort {
// Sort using a completely random comparison function.
// This will reorder the elements *somehow*, but won't panic.
let mut v: Vec<_> = (0..100).collect();
v.$f(|_, _| *thread_rng().choose(&[Less, Equal, Greater]).unwrap());
v.$f(|_, _| *[Less, Equal, Greater].choose(&mut thread_rng()).unwrap());
v.$f(|a, b| a.cmp(b));
for i in 0..v.len() {
assert_eq!(v[i], i);
Expand Down Expand Up @@ -101,9 +102,10 @@ fn test_par_sort_stability() {
// the second item represents which occurrence of that
// number this element is, i.e. the second elements
// will occur in sorted order.
let mut rng = thread_rng();
let mut v: Vec<_> = (0..len)
.map(|_| {
let n = thread_rng().gen_range::<usize>(0, 10);
let n: usize = rng.gen_range(0, 10);
counts[n] += 1;
(n, counts[n])
})
Expand Down
4 changes: 3 additions & 1 deletion tests/str.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
extern crate rand;
extern crate rand_xorshift;
extern crate rayon;

use rand::distributions::Standard;
use rand::{Rng, SeedableRng, XorShiftRng};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use rayon::prelude::*;

fn seeded_rng() -> XorShiftRng {
Expand Down

0 comments on commit abd942e

Please sign in to comment.