Skip to content

Commit 5ab292d

Browse files
authored
Merge pull request #722 from rust-ndarray/update-par-azip
Update `par_azip!()` syntax to match `azip!()`
2 parents 0446d5b + 0c1a3d7 commit 5ab292d

File tree

5 files changed

+40
-76
lines changed

5 files changed

+40
-76
lines changed

benches/par_rayon.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn rayon_add(bench: &mut Bencher) {
131131
let c = Array2::<f64>::zeros((ADDN, ADDN));
132132
let d = Array2::<f64>::zeros((ADDN, ADDN));
133133
bench.iter(|| {
134-
par_azip!(mut a, b, c, d in {
134+
par_azip!((a in &mut a, b in &b, c in &c, d in &d) {
135135
*a += b.exp() + c.exp() + d.exp();
136136
});
137137
});

src/parallel/zipmacro.rs

+6-51
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
/// This is a version of the [`azip`] macro that requires the crate feature
1414
/// `rayon` to be enabled.
1515
///
16+
/// See the [`azip`] macro for more details about the macro syntax!
17+
///
1618
/// This example:
1719
///
1820
/// ```rust,ignore
19-
/// par_azip!(mut a, b, c in { *a = b + c })
21+
/// par_azip!((a in &mut a, &b in &b, &c in &c) { *a = b + c })
2022
/// ```
2123
///
2224
/// Is equivalent to:
@@ -47,60 +49,13 @@
4749
/// // Compute a simple ternary operation:
4850
/// // elementwise addition of b and c, stored in a
4951
///
50-
/// par_azip!(mut a, b, c in { *a = b + c });
52+
/// par_azip!((a in &mut a, &b in &b, &c in &c) *a = b + c);
5153
///
5254
/// assert_eq!(a, &b + &c);
5355
/// }
5456
/// ```
5557
macro_rules! par_azip {
56-
// Build Zip Rule (index)
57-
(@parse [index => $a:expr, $($aa:expr,)*] $t1:tt in $t2:tt) => {
58-
$crate::par_azip!(@finish ($crate::Zip::indexed($a)) [$($aa,)*] $t1 in $t2)
59-
};
60-
// Build Zip Rule (no index)
61-
(@parse [$a:expr, $($aa:expr,)*] $t1:tt in $t2:tt) => {
62-
$crate::par_azip!(@finish ($crate::Zip::from($a)) [$($aa,)*] $t1 in $t2)
63-
};
64-
// Build Finish Rule (both)
65-
(@finish ($z:expr) [$($aa:expr,)*] [$($p:pat,)+] in { $($t:tt)*}) => {
66-
use $crate::parallel::prelude::*;
67-
#[allow(unused_mut)]
68-
($z)
69-
$(
70-
.and($aa)
71-
)*
72-
.par_apply(|$($p),+| {
73-
$($t)*
74-
})
75-
};
76-
// parsing stack: [expressions] [patterns] (one per operand)
77-
// index uses empty [] -- must be first
78-
(@parse [] [] index $i:pat, $($t:tt)*) => {
79-
$crate::par_azip!(@parse [index =>] [$i,] $($t)*);
80-
};
81-
(@parse [$($exprs:tt)*] [$($pats:tt)*] mut $x:ident ($e:expr) $($t:tt)*) => {
82-
$crate::par_azip!(@parse [$($exprs)* $e,] [$($pats)* mut $x,] $($t)*);
83-
};
84-
(@parse [$($exprs:tt)*] [$($pats:tt)*] mut $x:ident $($t:tt)*) => {
85-
$crate::par_azip!(@parse [$($exprs)* &mut $x,] [$($pats)* mut $x,] $($t)*);
86-
};
87-
(@parse [$($exprs:tt)*] [$($pats:tt)*] , $($t:tt)*) => {
88-
$crate::par_azip!(@parse [$($exprs)*] [$($pats)*] $($t)*);
89-
};
90-
(@parse [$($exprs:tt)*] [$($pats:tt)*] ref $x:ident ($e:expr) $($t:tt)*) => {
91-
$crate::par_azip!(@parse [$($exprs)* $e,] [$($pats)* $x,] $($t)*);
92-
};
93-
(@parse [$($exprs:tt)*] [$($pats:tt)*] ref $x:ident $($t:tt)*) => {
94-
$crate::par_azip!(@parse [$($exprs)* &$x,] [$($pats)* $x,] $($t)*);
95-
};
96-
(@parse [$($exprs:tt)*] [$($pats:tt)*] $x:ident ($e:expr) $($t:tt)*) => {
97-
$crate::par_azip!(@parse [$($exprs)* $e,] [$($pats)* &$x,] $($t)*);
98-
};
99-
(@parse [$($exprs:tt)*] [$($pats:tt)*] $x:ident $($t:tt)*) => {
100-
$crate::par_azip!(@parse [$($exprs)* &$x,] [$($pats)* &$x,] $($t)*);
101-
};
102-
(@parse [$($exprs:tt)*] [$($pats:tt)*] $($t:tt)*) => { };
10358
($($t:tt)*) => {
104-
$crate::par_azip!(@parse [] [] $($t)*);
105-
}
59+
$crate::azip!(@build par_apply $($t)*)
60+
};
10661
}

src/zip/zipmacro.rs

+17-19
Original file line numberDiff line numberDiff line change
@@ -101,32 +101,30 @@
101101
/// ```
102102
#[macro_export]
103103
macro_rules! azip {
104-
// Indexed with a single producer and no trailing comma.
105-
((index $index:pat, $first_pat:pat in $first_prod:expr) $body:expr) => {
106-
$crate::Zip::indexed($first_prod).apply(|$index, $first_pat| $body)
104+
// Indexed with a single producer
105+
// we allow an optional trailing comma after the producers in each rule.
106+
(@build $apply:ident (index $index:pat, $first_pat:pat in $first_prod:expr $(,)?) $body:expr) => {
107+
$crate::Zip::indexed($first_prod).$apply(|$index, $first_pat| $body)
107108
};
108-
// Indexed with more than one producer and no trailing comma.
109-
((index $index:pat, $first_pat:pat in $first_prod:expr, $($pat:pat in $prod:expr),*) $body:expr) => {
109+
// Indexed with more than one producer
110+
(@build $apply:ident (index $index:pat, $first_pat:pat in $first_prod:expr, $($pat:pat in $prod:expr),* $(,)?) $body:expr) => {
110111
$crate::Zip::indexed($first_prod)
111112
$(.and($prod))*
112-
.apply(|$index, $first_pat, $($pat),*| $body)
113+
.$apply(|$index, $first_pat, $($pat),*| $body)
113114
};
114-
// Indexed with trailing comma.
115-
((index $index:pat, $($pat:pat in $prod:expr),+,) $body:expr) => {
116-
azip!((index $index, $($pat in $prod),+) $body)
115+
// Unindexed with a single producer
116+
(@build $apply:ident ($first_pat:pat in $first_prod:expr $(,)?) $body:expr) => {
117+
$crate::Zip::from($first_prod).$apply(|$first_pat| $body)
117118
};
118-
// Unindexed with a single producer and no trailing comma.
119-
(($first_pat:pat in $first_prod:expr) $body:expr) => {
120-
$crate::Zip::from($first_prod).apply(|$first_pat| $body)
121-
};
122-
// Unindexed with more than one producer and no trailing comma.
123-
(($first_pat:pat in $first_prod:expr, $($pat:pat in $prod:expr),*) $body:expr) => {
119+
// Unindexed with more than one producer
120+
(@build $apply:ident ($first_pat:pat in $first_prod:expr, $($pat:pat in $prod:expr),* $(,)?) $body:expr) => {
124121
$crate::Zip::from($first_prod)
125122
$(.and($prod))*
126-
.apply(|$first_pat, $($pat),*| $body)
123+
.$apply(|$first_pat, $($pat),*| $body)
127124
};
128-
// Unindexed with trailing comma.
129-
(($($pat:pat in $prod:expr),+,) $body:expr) => {
130-
azip!(($($pat in $prod),+) $body)
125+
// catch-all rule
126+
(@build $($t:tt)*) => { compile_error!("Invalid syntax in azip!()") };
127+
($($t:tt)*) => {
128+
$crate::azip!(@build apply $($t)*)
131129
};
132130
}

tests/azip.rs

+10
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ fn test_azip2_3() {
4949
assert!(a != b);
5050
}
5151

52+
#[test]
53+
fn test_azip_syntax_trailing_comma() {
54+
let mut b = Array::<i32, _>::zeros((5, 5));
55+
let mut c = Array::<i32, _>::ones((5, 5));
56+
let a = b.clone();
57+
azip!((b in &mut b, c in &mut c, ) swap(b, c));
58+
assert_eq!(a, c);
59+
assert!(a != b);
60+
}
61+
5262
#[test]
5363
#[cfg(feature = "approx")]
5464
fn test_azip2_sum() {

tests/par_azip.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![cfg(feature = "rayon")]
22

3+
#[cfg(feature = "approx")]
34
use itertools::enumerate;
45
use ndarray::parallel::prelude::*;
56
use ndarray::prelude::*;
@@ -9,15 +10,15 @@ use std::sync::atomic::{AtomicUsize, Ordering};
910
fn test_par_azip1() {
1011
let mut a = Array::zeros(62);
1112
let b = Array::from_elem(62, 42);
12-
par_azip!(mut a in { *a = 42 });
13+
par_azip!((a in &mut a) { *a = 42 });
1314
assert_eq!(a, b);
1415
}
1516

1617
#[test]
1718
fn test_par_azip2() {
1819
let mut a = Array::zeros((5, 7));
1920
let b = Array::from_shape_fn(a.dim(), |(i, j)| 1. / (i + 2 * j) as f32);
20-
par_azip!(mut a, b in { *a = b; });
21+
par_azip!((a in &mut a, &b in &b, ) *a = b );
2122
assert_eq!(a, b);
2223
}
2324

@@ -33,7 +34,7 @@ fn test_par_azip3() {
3334
*elt = i as f32;
3435
}
3536

36-
par_azip!(mut a (&mut a[..]), b (&b[..]), mut c (&mut c[..]) in {
37+
par_azip!((a in &mut a[..], &b in &b[..], c in &mut c[..]) {
3738
*a += b / 10.;
3839
*c = a.sin();
3940
});
@@ -48,7 +49,7 @@ fn test_zip_dim_mismatch_1() {
4849
let mut d = a.raw_dim();
4950
d[0] += 1;
5051
let b = Array::from_shape_fn(d, |(i, j)| 1. / (i + 2 * j) as f32);
51-
par_azip!(mut a, b in { *a = b; });
52+
par_azip!((a in &mut a, &b in &b) { *a = b; });
5253
}
5354

5455
#[test]
@@ -59,7 +60,7 @@ fn test_indices_1() {
5960
}
6061

6162
let count = AtomicUsize::new(0);
62-
par_azip!(index i, elt (&a1) in {
63+
par_azip!((index i, &elt in &a1) {
6364
count.fetch_add(1, Ordering::SeqCst);
6465
assert_eq!(elt, i);
6566
});

0 commit comments

Comments
 (0)