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²⁷
octillion() -> rayon::range::Iter<u128>6 fn octillion() -> rayon::range::Iter<u128> {
7     (0..OCTILLION).into_par_iter()
8 }
9 
10 /// Produce a parallel iterator for 0u128..=10²⁷
octillion_inclusive() -> rayon::range_inclusive::Iter<u128>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`
octillion_flat() -> impl ParallelIterator<Item = u128>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)]
find_first_octillion()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)]
find_first_octillion_inclusive()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)]
find_first_octillion_flat()55 fn find_first_octillion_flat() {
56     let x = octillion_flat().find_first(|_| true);
57     assert_eq!(x, Some(0));
58 }
59 
two_threads<F: Send + FnOnce() -> R, R: Send>(f: F) -> R60 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 )]
find_last_octillion()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 )]
find_last_octillion_inclusive()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 )]
find_last_octillion_flat()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)]
find_any_octillion()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)]
find_any_octillion_flat()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)]
filter_find_any_octillion()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)]
filter_find_any_octillion_flat()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)]
fold_find_any_octillion_flat()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