Skip to content

Commit 6cb2368

Browse files
authored
Merge pull request #1389 from akern40/array_macro
Expands the `array!` macro.
2 parents 024dccb + e2facb7 commit 6cb2368

File tree

2 files changed

+81
-56
lines changed

2 files changed

+81
-56
lines changed

src/dimension/ndindex.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ unsafe impl NdIndex<Ix5> for (Ix, Ix, Ix, Ix, Ix)
113113
}
114114
}
115115

116+
unsafe impl NdIndex<Ix6> for (Ix, Ix, Ix, Ix, Ix, Ix)
117+
{
118+
#[inline]
119+
fn index_checked(&self, dim: &Ix6, strides: &Ix6) -> Option<isize>
120+
{
121+
dim.stride_offset_checked(strides, &self.into_dimension())
122+
}
123+
#[inline]
124+
fn index_unchecked(&self, strides: &Ix6) -> isize
125+
{
126+
zip(strides.ix(), self.into_dimension().ix())
127+
.map(|(&s, &i)| stride_offset(i, s))
128+
.sum()
129+
}
130+
}
131+
116132
unsafe impl NdIndex<Ix1> for Ix
117133
{
118134
#[inline]

src/free_functions.rs

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
use alloc::vec;
1010
#[cfg(not(feature = "std"))]
1111
use alloc::vec::Vec;
12+
#[allow(unused_imports)]
13+
use std::compile_error;
1214
use std::mem::{forget, size_of};
1315
use std::ptr::NonNull;
1416

1517
use crate::imp_prelude::*;
1618
use crate::{dimension, ArcArray1, ArcArray2};
1719

18-
/// Create an **[`Array`]** with one, two or
19-
/// three dimensions.
20+
/// Create an **[`Array`]** with one, two, three, four, five, or six dimensions.
2021
///
2122
/// ```
2223
/// use ndarray::array;
@@ -28,17 +29,49 @@ use crate::{dimension, ArcArray1, ArcArray2};
2829
/// let a3 = array![[[1, 2], [3, 4]],
2930
/// [[5, 6], [7, 8]]];
3031
///
32+
/// let a4 = array![[[[1, 2, 3, 4]]]];
33+
///
34+
/// let a5 = array![[[[[1, 2, 3, 4, 5]]]]];
35+
///
36+
/// let a6 = array![[[[[[1, 2, 3, 4, 5, 6]]]]]];
37+
///
3138
/// assert_eq!(a1.shape(), &[4]);
3239
/// assert_eq!(a2.shape(), &[2, 2]);
3340
/// assert_eq!(a3.shape(), &[2, 2, 2]);
41+
/// assert_eq!(a4.shape(), &[1, 1, 1, 4]);
42+
/// assert_eq!(a5.shape(), &[1, 1, 1, 1, 5]);
43+
/// assert_eq!(a6.shape(), &[1, 1, 1, 1, 1, 6]);
3444
/// ```
3545
///
3646
/// This macro uses `vec![]`, and has the same ownership semantics;
3747
/// elements are moved into the resulting `Array`.
3848
///
3949
/// Use `array![...].into_shared()` to create an `ArcArray`.
50+
///
51+
/// Attempts to crate 7D+ arrays with this macro will lead to
52+
/// a compiler error, since the difference between a 7D array
53+
/// of i32 and a 6D array of `[i32; 3]` is ambiguous. Higher-dim
54+
/// arrays can be created with [`ArrayD`].
55+
///
56+
/// ```compile_fail
57+
/// use ndarray::array;
58+
/// let a7 = array![[[[[[[1, 2, 3]]]]]]];
59+
/// // error: Arrays of 7 dimensions or more (or ndarrays of Rust arrays) cannot be constructed with the array! macro.
60+
/// ```
4061
#[macro_export]
4162
macro_rules! array {
63+
($([$([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
64+
compile_error!("Arrays of 7 dimensions or more (or ndarrays of Rust arrays) cannot be constructed with the array! macro.");
65+
}};
66+
($([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
67+
$crate::Array6::from(vec![$([$([$([$([$([$($x,)*],)*],)*],)*],)*],)*])
68+
}};
69+
($([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
70+
$crate::Array5::from(vec![$([$([$([$([$($x,)*],)*],)*],)*],)*])
71+
}};
72+
($([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
73+
$crate::Array4::from(vec![$([$([$([$($x,)*],)*],)*],)*])
74+
}};
4275
($([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*) => {{
4376
$crate::Array3::from(vec![$([$([$($x,)*],)*],)*])
4477
}};
@@ -233,63 +266,39 @@ pub fn arr2<A: Clone, const N: usize>(xs: &[[A; N]]) -> Array2<A>
233266
Array2::from(xs.to_vec())
234267
}
235268

236-
impl<A, const N: usize> From<Vec<[A; N]>> for Array2<A>
237-
{
238-
/// Converts the `Vec` of arrays to an owned 2-D array.
239-
///
240-
/// **Panics** if the product of non-zero axis lengths overflows `isize`.
241-
fn from(mut xs: Vec<[A; N]>) -> Self
242-
{
243-
let dim = Ix2(xs.len(), N);
244-
let ptr = xs.as_mut_ptr();
245-
let cap = xs.capacity();
246-
let expand_len =
247-
dimension::size_of_shape_checked(&dim).expect("Product of non-zero axis lengths must not overflow isize.");
248-
forget(xs);
249-
unsafe {
250-
let v = if size_of::<A>() == 0 {
251-
Vec::from_raw_parts(ptr as *mut A, expand_len, expand_len)
252-
} else if N == 0 {
253-
Vec::new()
254-
} else {
255-
// Guaranteed not to overflow in this case since A is non-ZST
256-
// and Vec never allocates more than isize bytes.
257-
let expand_cap = cap * N;
258-
Vec::from_raw_parts(ptr as *mut A, expand_len, expand_cap)
259-
};
260-
ArrayBase::from_shape_vec_unchecked(dim, v)
269+
macro_rules! impl_from_nested_vec {
270+
($arr_type:ty, $ix_type:tt, $($n:ident),+) => {
271+
impl<A, $(const $n: usize),+> From<Vec<$arr_type>> for Array<A, $ix_type>
272+
{
273+
fn from(mut xs: Vec<$arr_type>) -> Self
274+
{
275+
let dim = $ix_type(xs.len(), $($n),+);
276+
let ptr = xs.as_mut_ptr();
277+
let cap = xs.capacity();
278+
let expand_len = dimension::size_of_shape_checked(&dim)
279+
.expect("Product of non-zero axis lengths must not overflow isize.");
280+
forget(xs);
281+
unsafe {
282+
let v = if size_of::<A>() == 0 {
283+
Vec::from_raw_parts(ptr as *mut A, expand_len, expand_len)
284+
} else if $($n == 0 ||)+ false {
285+
Vec::new()
286+
} else {
287+
let expand_cap = cap $(* $n)+;
288+
Vec::from_raw_parts(ptr as *mut A, expand_len, expand_cap)
289+
};
290+
ArrayBase::from_shape_vec_unchecked(dim, v)
291+
}
292+
}
261293
}
262-
}
294+
};
263295
}
264296

265-
impl<A, const N: usize, const M: usize> From<Vec<[[A; M]; N]>> for Array3<A>
266-
{
267-
/// Converts the `Vec` of arrays to an owned 3-D array.
268-
///
269-
/// **Panics** if the product of non-zero axis lengths overflows `isize`.
270-
fn from(mut xs: Vec<[[A; M]; N]>) -> Self
271-
{
272-
let dim = Ix3(xs.len(), N, M);
273-
let ptr = xs.as_mut_ptr();
274-
let cap = xs.capacity();
275-
let expand_len =
276-
dimension::size_of_shape_checked(&dim).expect("Product of non-zero axis lengths must not overflow isize.");
277-
forget(xs);
278-
unsafe {
279-
let v = if size_of::<A>() == 0 {
280-
Vec::from_raw_parts(ptr as *mut A, expand_len, expand_len)
281-
} else if N == 0 || M == 0 {
282-
Vec::new()
283-
} else {
284-
// Guaranteed not to overflow in this case since A is non-ZST
285-
// and Vec never allocates more than isize bytes.
286-
let expand_cap = cap * N * M;
287-
Vec::from_raw_parts(ptr as *mut A, expand_len, expand_cap)
288-
};
289-
ArrayBase::from_shape_vec_unchecked(dim, v)
290-
}
291-
}
292-
}
297+
impl_from_nested_vec!([A; N], Ix2, N);
298+
impl_from_nested_vec!([[A; M]; N], Ix3, N, M);
299+
impl_from_nested_vec!([[[A; L]; M]; N], Ix4, N, M, L);
300+
impl_from_nested_vec!([[[[A; K]; L]; M]; N], Ix5, N, M, L, K);
301+
impl_from_nested_vec!([[[[[A; J]; K]; L]; M]; N], Ix6, N, M, L, K, J);
293302

294303
/// Create a two-dimensional array with elements from `xs`.
295304
///

0 commit comments

Comments
 (0)