1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#![warn(clippy::all)]

cfg_if::cfg_if! {
  if #[cfg(any(not(feature = "threads"), all(target_arch="wasm32", not(target_feature = "atomics"))))] {
    #[derive(Default)]
    pub struct ThreadPoolBuilder ();
    impl ThreadPoolBuilder {
      #[inline(always)]
      pub fn new() -> ThreadPoolBuilder {
        ThreadPoolBuilder()
      }

      #[inline(always)]
      pub fn build(self) -> Result<ThreadPool, ::core::convert::Infallible> {
        Ok(ThreadPool())
      }

      #[inline(always)]
      pub fn num_threads(self, _num_threads: usize) -> ThreadPoolBuilder {
        ThreadPoolBuilder()
      }
    }
    #[derive(Debug)]
    pub struct ThreadPool ();
    impl ThreadPool {
      #[inline(always)]
      pub fn install<OP, R>(&self, op: OP) -> R where
            OP: FnOnce() -> R + Send,
                R: Send, {
        op()
      }
    }

    pub mod iter {
      pub trait IntoParallelIterator {
          type Iter: Iterator<Item = Self::Item>;
          type Item: Send;

          fn into_par_iter(self) -> Self::Iter;
      }

      impl<I: IntoIterator> IntoParallelIterator for I where
        I::Item : Send {
        type Item = I::Item;
        type Iter = I::IntoIter;

        #[inline(always)]
        fn into_par_iter(self) -> I::IntoIter {
          self.into_iter()
        }
      }

      pub trait IntoParallelRefMutIterator<'data> {
          type Iter: IntoParallelIterator<Item = Self::Item>;
          type Item: Send + 'data;

          fn par_iter_mut(&'data mut self) -> Self::Iter;
      }

      impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I
      where
          &'data mut I: IntoParallelIterator,
      {
          type Iter = <&'data mut I as IntoParallelIterator>::Iter;
          type Item = <&'data mut I as IntoParallelIterator>::Item;

          #[inline(always)]
          fn par_iter_mut(&'data mut self) -> Self::Iter {
              self.into_par_iter()
          }
      }

      pub trait ParallelIterator: Iterator {
        #[inline(always)]
        fn flat_map_iter<U, F>(self, f: F) -> std::iter::FlatMap<Self, U, F>
        where
          Self: Sized,
          U: IntoIterator,
          F: FnMut(<Self as Iterator>::Item) -> U,
        {
          self.flat_map(f)
        }
      }

      impl<I: Iterator> ParallelIterator for I {}
    }
    pub mod slice {
      pub trait ParallelSlice<T: Sync> {
        fn par_chunks_exact(
          &self, chunk_size: usize,
        ) -> std::slice::ChunksExact<'_, T>;
      }

      impl<T: Sync> ParallelSlice<T> for [T] {
        #[inline(always)]
        fn par_chunks_exact(
          &self, chunk_size: usize,
        ) -> std::slice::ChunksExact<'_, T> {
          self.chunks_exact(chunk_size)
        }
      }
    }

    pub mod prelude {
      pub use super::iter::*;
      pub use super::slice::*;
    }

    #[inline(always)]
    pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where
      A: FnOnce() -> RA + Send,
      B: FnOnce() -> RB + Send,
      RA: Send,
      RB: Send {
      (oper_a(), oper_b())
    }

    use std::marker::PhantomData;

    pub struct Scope<'scope>{
      #[allow(clippy::type_complexity)]
      marker: PhantomData<Box<dyn FnOnce(&Scope<'scope>) + Send + Sync + 'scope>>,
    }

    impl<'scope> Scope<'scope> {
      #[inline(always)]
      pub fn spawn<BODY>(&self, body: BODY)
        where BODY: FnOnce(&Scope<'scope>) + Send + 'scope
      {
        body(self)
      }
    }

    #[inline(always)]
    pub fn scope<'scope, OP, R>(op: OP) -> R
      where OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send, R: Send,
    {
      op(&Scope { marker: PhantomData })
    }
  } else {
    pub use rayon::*;
  }
}