1 | use rayon::prelude::*; |
2 | |
3 | const OCTILLION: u128 = 1_000_000_000_000_000_000_000_000_000; |
4 | |
5 | /// Produce a parallel iterator for 0u128..10²⁷ |
6 | fn octillion() -> rayon::range::Iter<u128> { |
7 | (0..OCTILLION).into_par_iter() |
8 | } |
9 | |
10 | /// Produce a parallel iterator for 0u128..=10²⁷ |
11 | fn octillion_inclusive() -> rayon::range_inclusive::Iter<u128> { |
12 | (0..=OCTILLION).into_par_iter() |
13 | } |
14 | |
15 | /// Produce a parallel iterator for 0u128..10²⁷ using `flat_map` |
16 | fn octillion_flat() -> impl ParallelIterator<Item = u128> { |
17 | (0u32..1_000_000_000) |
18 | .into_par_iter() |
19 | .with_max_len(1_000) |
20 | .map(|i| u64::from(i) * 1_000_000_000) |
21 | .flat_map(|i| { |
22 | (0u32..1_000_000_000) |
23 | .into_par_iter() |
24 | .with_max_len(1_000) |
25 | .map(move |j| i + u64::from(j)) |
26 | }) |
27 | .map(|i| u128::from(i) * 1_000_000_000) |
28 | .flat_map(|i| { |
29 | (0u32..1_000_000_000) |
30 | .into_par_iter() |
31 | .with_max_len(1_000) |
32 | .map(move |j| i + u128::from(j)) |
33 | }) |
34 | } |
35 | |
36 | // NOTE: `find_first` and `find_last` currently take too long on 32-bit targets, |
37 | // because the `AtomicUsize` match position has much too limited resolution. |
38 | |
39 | #[test] |
40 | #[cfg_attr (not(target_pointer_width = "64" ), ignore)] |
41 | fn find_first_octillion() { |
42 | let x = octillion().find_first(|_| true); |
43 | assert_eq!(x, Some(0)); |
44 | } |
45 | |
46 | #[test] |
47 | #[cfg_attr (not(target_pointer_width = "64" ), ignore)] |
48 | fn find_first_octillion_inclusive() { |
49 | let x = octillion_inclusive().find_first(|_| true); |
50 | assert_eq!(x, Some(0)); |
51 | } |
52 | |
53 | #[test] |
54 | #[cfg_attr (not(target_pointer_width = "64" ), ignore)] |
55 | fn find_first_octillion_flat() { |
56 | let x = octillion_flat().find_first(|_| true); |
57 | assert_eq!(x, Some(0)); |
58 | } |
59 | |
60 | fn two_threads<F: Send + FnOnce() -> R, R: Send>(f: F) -> R { |
61 | // FIXME: If we don't use at least two threads, then we end up walking |
62 | // through the entire iterator sequentially, without the benefit of any |
63 | // short-circuiting. We probably don't want testing to wait that long. ;) |
64 | let builder = rayon::ThreadPoolBuilder::new().num_threads(2); |
65 | let pool = builder.build().unwrap(); |
66 | |
67 | pool.install(f) |
68 | } |
69 | |
70 | #[test] |
71 | #[cfg_attr ( |
72 | any( |
73 | not(target_pointer_width = "64" ), |
74 | target_os = "emscripten" , |
75 | target_family = "wasm" |
76 | ), |
77 | ignore |
78 | )] |
79 | fn find_last_octillion() { |
80 | // It would be nice if `find_last` could prioritize the later splits, |
81 | // basically flipping the `join` args, without needing indexed `rev`. |
82 | // (or could we have an unindexed `rev`?) |
83 | let x = two_threads(|| octillion().find_last(|_| true)); |
84 | assert_eq!(x, Some(OCTILLION - 1)); |
85 | } |
86 | |
87 | #[test] |
88 | #[cfg_attr ( |
89 | any( |
90 | not(target_pointer_width = "64" ), |
91 | target_os = "emscripten" , |
92 | target_family = "wasm" |
93 | ), |
94 | ignore |
95 | )] |
96 | fn find_last_octillion_inclusive() { |
97 | let x = two_threads(|| octillion_inclusive().find_last(|_| true)); |
98 | assert_eq!(x, Some(OCTILLION)); |
99 | } |
100 | |
101 | #[test] |
102 | #[cfg_attr ( |
103 | any( |
104 | not(target_pointer_width = "64" ), |
105 | target_os = "emscripten" , |
106 | target_family = "wasm" |
107 | ), |
108 | ignore |
109 | )] |
110 | fn find_last_octillion_flat() { |
111 | let x = two_threads(|| octillion_flat().find_last(|_| true)); |
112 | assert_eq!(x, Some(OCTILLION - 1)); |
113 | } |
114 | |
115 | #[test] |
116 | #[cfg_attr (any(target_os = "emscripten" , target_family = "wasm" ), ignore)] |
117 | fn find_any_octillion() { |
118 | let x = two_threads(|| octillion().find_any(|x| *x > OCTILLION / 2)); |
119 | assert!(x.is_some()); |
120 | } |
121 | |
122 | #[test] |
123 | #[cfg_attr (any(target_os = "emscripten" , target_family = "wasm" ), ignore)] |
124 | fn find_any_octillion_flat() { |
125 | let x = two_threads(|| octillion_flat().find_any(|x| *x > OCTILLION / 2)); |
126 | assert!(x.is_some()); |
127 | } |
128 | |
129 | #[test] |
130 | #[cfg_attr (any(target_os = "emscripten" , target_family = "wasm" ), ignore)] |
131 | fn filter_find_any_octillion() { |
132 | let x = two_threads(|| { |
133 | octillion() |
134 | .filter(|x| *x > OCTILLION / 2) |
135 | .find_any(|_| true) |
136 | }); |
137 | assert!(x.is_some()); |
138 | } |
139 | |
140 | #[test] |
141 | #[cfg_attr (any(target_os = "emscripten" , target_family = "wasm" ), ignore)] |
142 | fn filter_find_any_octillion_flat() { |
143 | let x = two_threads(|| { |
144 | octillion_flat() |
145 | .filter(|x| *x > OCTILLION / 2) |
146 | .find_any(|_| true) |
147 | }); |
148 | assert!(x.is_some()); |
149 | } |
150 | |
151 | #[test] |
152 | #[cfg_attr (any(target_os = "emscripten" , target_family = "wasm" ), ignore)] |
153 | fn fold_find_any_octillion_flat() { |
154 | let x = two_threads(|| octillion_flat().fold(|| (), |_, _| ()).find_any(|_| true)); |
155 | assert!(x.is_some()); |
156 | } |
157 | |