Skip to content

Commit 3b775bf

Browse files
authored
feat: Add parallel iterators (#10075)
**Description:** I introduced `swc_par_iter`, which uses `swc_parallel` for `join` operations. It's not perfect, but this PR looks like a good starting point. I decided to implement it in a separate crate than `chili` because I need the ability to switch parallelization library.
1 parent a23ee8a commit 3b775bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+27837
-2
lines changed

Cargo.lock

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/swc_par_iter/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
description = "Fork of rayon, with chili support"
3+
edition = { workspace = true }
4+
license = { workspace = true }
5+
name = "swc_par_iter"
6+
repository = { workspace = true }
7+
version = "1.0.0"
8+
9+
[dependencies]
10+
either = { workspace = true }
11+
swc_parallel = { version = "1.3.0", path = "../swc_parallel", default-features = false }
12+
13+
[dev-dependencies]
14+
chili = { workspace = true }
15+
rand = { workspace = true }
16+
rand_xorshift = "0.3"
17+
swc_parallel = { version = "1.3.0", path = "../swc_parallel", default-features = false, features = [
18+
"chili",
19+
] }

crates/swc_par_iter/src/array.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! Parallel iterator types for [arrays] (`[T; N]`)
2+
//!
3+
//! You will rarely need to interact with this module directly unless you need
4+
//! to name one of the iterator types.
5+
//!
6+
//! [arrays]: https://doc.rust-lang.org/std/primitive.array.html
7+
8+
use std::mem::ManuallyDrop;
9+
10+
use crate::{
11+
iter::{plumbing::*, *},
12+
slice::{Iter, IterMut},
13+
vec::DrainProducer,
14+
};
15+
16+
impl<'data, T: Sync + 'data, const N: usize> IntoParallelIterator for &'data [T; N] {
17+
type Item = &'data T;
18+
type Iter = Iter<'data, T>;
19+
20+
fn into_par_iter(self) -> Self::Iter {
21+
<&[T]>::into_par_iter(self)
22+
}
23+
}
24+
25+
impl<'data, T: Send + 'data, const N: usize> IntoParallelIterator for &'data mut [T; N] {
26+
type Item = &'data mut T;
27+
type Iter = IterMut<'data, T>;
28+
29+
fn into_par_iter(self) -> Self::Iter {
30+
<&mut [T]>::into_par_iter(self)
31+
}
32+
}
33+
34+
impl<T: Send, const N: usize> IntoParallelIterator for [T; N] {
35+
type Item = T;
36+
type Iter = IntoIter<T, N>;
37+
38+
fn into_par_iter(self) -> Self::Iter {
39+
IntoIter { array: self }
40+
}
41+
}
42+
43+
/// Parallel iterator that moves out of an array.
44+
#[derive(Debug, Clone)]
45+
pub struct IntoIter<T: Send, const N: usize> {
46+
array: [T; N],
47+
}
48+
49+
impl<T: Send, const N: usize> ParallelIterator for IntoIter<T, N> {
50+
type Item = T;
51+
52+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
53+
where
54+
C: UnindexedConsumer<Self::Item>,
55+
{
56+
bridge(self, consumer)
57+
}
58+
59+
fn opt_len(&self) -> Option<usize> {
60+
Some(N)
61+
}
62+
}
63+
64+
impl<T: Send, const N: usize> IndexedParallelIterator for IntoIter<T, N> {
65+
fn drive<C>(self, consumer: C) -> C::Result
66+
where
67+
C: Consumer<Self::Item>,
68+
{
69+
bridge(self, consumer)
70+
}
71+
72+
fn len(&self) -> usize {
73+
N
74+
}
75+
76+
fn with_producer<CB>(self, callback: CB) -> CB::Output
77+
where
78+
CB: ProducerCallback<Self::Item>,
79+
{
80+
unsafe {
81+
// Drain every item, and then the local array can just fall out of scope.
82+
let mut array = ManuallyDrop::new(self.array);
83+
let producer = DrainProducer::new(array.as_mut_slice());
84+
callback.callback(producer)
85+
}
86+
}
87+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//! This module contains the parallel iterator types for heaps
2+
//! (`BinaryHeap<T>`). You will rarely need to interact with it directly
3+
//! unless you have need to name one of the iterator types.
4+
5+
use std::collections::BinaryHeap;
6+
7+
use crate::{
8+
iter::{plumbing::*, *},
9+
vec,
10+
};
11+
12+
/// Parallel iterator over a binary heap
13+
#[derive(Debug, Clone)]
14+
pub struct IntoIter<T: Ord + Send> {
15+
inner: vec::IntoIter<T>,
16+
}
17+
18+
impl<T: Ord + Send> IntoParallelIterator for BinaryHeap<T> {
19+
type Item = T;
20+
type Iter = IntoIter<T>;
21+
22+
fn into_par_iter(self) -> Self::Iter {
23+
IntoIter {
24+
inner: Vec::from(self).into_par_iter(),
25+
}
26+
}
27+
}
28+
29+
delegate_indexed_iterator! {
30+
IntoIter<T> => T,
31+
impl<T: Ord + Send>
32+
}
33+
34+
/// Parallel iterator over an immutable reference to a binary heap
35+
#[derive(Debug)]
36+
pub struct Iter<'a, T: Ord + Sync> {
37+
// TODO (MSRV 1.80): this could use `slice::Iter` built from
38+
// `BinaryHeap::as_slice`, rather than using a temp `Vec<&T>`.
39+
inner: vec::IntoIter<&'a T>,
40+
}
41+
42+
impl<'a, T: Ord + Sync> Clone for Iter<'a, T> {
43+
fn clone(&self) -> Self {
44+
Iter {
45+
inner: self.inner.clone(),
46+
}
47+
}
48+
}
49+
50+
into_par_vec! {
51+
&'a BinaryHeap<T> => Iter<'a, T>,
52+
impl<'a, T: Ord + Sync>
53+
}
54+
55+
delegate_indexed_iterator! {
56+
Iter<'a, T> => &'a T,
57+
impl<'a, T: Ord + Sync + 'a>
58+
}
59+
60+
// `BinaryHeap` doesn't have a mutable `Iterator`
61+
62+
/// Draining parallel iterator that moves out of a binary heap,
63+
/// but keeps the total capacity.
64+
#[derive(Debug)]
65+
pub struct Drain<'a, T: Ord + Send> {
66+
heap: &'a mut BinaryHeap<T>,
67+
}
68+
69+
impl<'a, T: Ord + Send> ParallelDrainFull for &'a mut BinaryHeap<T> {
70+
type Item = T;
71+
type Iter = Drain<'a, T>;
72+
73+
fn par_drain(self) -> Self::Iter {
74+
Drain { heap: self }
75+
}
76+
}
77+
78+
impl<'a, T: Ord + Send> ParallelIterator for Drain<'a, T> {
79+
type Item = T;
80+
81+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
82+
where
83+
C: UnindexedConsumer<Self::Item>,
84+
{
85+
bridge(self, consumer)
86+
}
87+
88+
fn opt_len(&self) -> Option<usize> {
89+
Some(self.len())
90+
}
91+
}
92+
93+
impl<'a, T: Ord + Send> IndexedParallelIterator for Drain<'a, T> {
94+
fn drive<C>(self, consumer: C) -> C::Result
95+
where
96+
C: Consumer<Self::Item>,
97+
{
98+
bridge(self, consumer)
99+
}
100+
101+
fn len(&self) -> usize {
102+
self.heap.len()
103+
}
104+
105+
fn with_producer<CB>(self, callback: CB) -> CB::Output
106+
where
107+
CB: ProducerCallback<Self::Item>,
108+
{
109+
super::DrainGuard::new(self.heap)
110+
.par_drain(..)
111+
.with_producer(callback)
112+
}
113+
}
114+
115+
impl<'a, T: Ord + Send> Drop for Drain<'a, T> {
116+
fn drop(&mut self) {
117+
if !self.heap.is_empty() {
118+
// We must not have produced, so just call a normal drain to remove the items.
119+
self.heap.drain();
120+
}
121+
}
122+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! This module contains the parallel iterator types for B-Tree maps
2+
//! (`BTreeMap<K, V>`). You will rarely need to interact with it directly
3+
//! unless you have need to name one of the iterator types.
4+
5+
use std::collections::BTreeMap;
6+
7+
use crate::{
8+
iter::{plumbing::*, *},
9+
vec,
10+
};
11+
12+
/// Parallel iterator over a B-Tree map
13+
#[derive(Debug)] // std doesn't Clone
14+
pub struct IntoIter<K: Ord + Send, V: Send> {
15+
inner: vec::IntoIter<(K, V)>,
16+
}
17+
18+
into_par_vec! {
19+
BTreeMap<K, V> => IntoIter<K, V>,
20+
impl<K: Ord + Send, V: Send>
21+
}
22+
23+
delegate_iterator! {
24+
IntoIter<K, V> => (K, V),
25+
impl<K: Ord + Send, V: Send>
26+
}
27+
28+
/// Parallel iterator over an immutable reference to a B-Tree map
29+
#[derive(Debug)]
30+
pub struct Iter<'a, K: Ord + Sync, V: Sync> {
31+
inner: vec::IntoIter<(&'a K, &'a V)>,
32+
}
33+
34+
impl<'a, K: Ord + Sync, V: Sync> Clone for Iter<'a, K, V> {
35+
fn clone(&self) -> Self {
36+
Iter {
37+
inner: self.inner.clone(),
38+
}
39+
}
40+
}
41+
42+
into_par_vec! {
43+
&'a BTreeMap<K, V> => Iter<'a, K, V>,
44+
impl<'a, K: Ord + Sync, V: Sync>
45+
}
46+
47+
delegate_iterator! {
48+
Iter<'a, K, V> => (&'a K, &'a V),
49+
impl<'a, K: Ord + Sync + 'a, V: Sync + 'a>
50+
}
51+
52+
/// Parallel iterator over a mutable reference to a B-Tree map
53+
#[derive(Debug)]
54+
pub struct IterMut<'a, K: Ord + Sync, V: Send> {
55+
inner: vec::IntoIter<(&'a K, &'a mut V)>,
56+
}
57+
58+
into_par_vec! {
59+
&'a mut BTreeMap<K, V> => IterMut<'a, K, V>,
60+
impl<'a, K: Ord + Sync, V: Send>
61+
}
62+
63+
delegate_iterator! {
64+
IterMut<'a, K, V> => (&'a K, &'a mut V),
65+
impl<'a, K: Ord + Sync + 'a, V: Send + 'a>
66+
}

0 commit comments

Comments
 (0)