ndarray/free_functions.rs
1// Copyright 2014-2016 bluss and ndarray developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::mem::{forget, size_of};
10use alloc::slice;
11use alloc::vec;
12use alloc::vec::Vec;
13
14use crate::imp_prelude::*;
15use crate::{dimension, ArcArray1, ArcArray2};
16
17/// Create an **[`Array`]** with one, two or
18/// three dimensions.
19///
20/// ```
21/// use ndarray::array;
22/// let a1 = array![1, 2, 3, 4];
23///
24/// let a2 = array![[1, 2],
25/// [3, 4]];
26///
27/// let a3 = array![[[1, 2], [3, 4]],
28/// [[5, 6], [7, 8]]];
29///
30/// assert_eq!(a1.shape(), &[4]);
31/// assert_eq!(a2.shape(), &[2, 2]);
32/// assert_eq!(a3.shape(), &[2, 2, 2]);
33/// ```
34///
35/// This macro uses `vec![]`, and has the same ownership semantics;
36/// elements are moved into the resulting `Array`.
37///
38/// Use `array![...].into_shared()` to create an `ArcArray`.
39#[macro_export]
40macro_rules! array {
41 ($([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*) => {{
42 $crate::Array3::from(vec![$([$([$($x,)*],)*],)*])
43 }};
44 ($([$($x:expr),* $(,)*]),+ $(,)*) => {{
45 $crate::Array2::from(vec![$([$($x,)*],)*])
46 }};
47 ($($x:expr),* $(,)*) => {{
48 $crate::Array::from(vec![$($x,)*])
49 }};
50}
51
52/// Create a zero-dimensional array with the element `x`.
53pub fn arr0<A>(x: A) -> Array0<A> {
54 unsafe { ArrayBase::from_shape_vec_unchecked((), vec![x]) }
55}
56
57/// Create a one-dimensional array with elements from `xs`.
58pub fn arr1<A: Clone>(xs: &[A]) -> Array1<A> {
59 ArrayBase::from(xs.to_vec())
60}
61
62/// Create a one-dimensional array with elements from `xs`.
63pub fn rcarr1<A: Clone>(xs: &[A]) -> ArcArray1<A> {
64 arr1(xs).into_shared()
65}
66
67/// Create a zero-dimensional array view borrowing `x`.
68pub fn aview0<A>(x: &A) -> ArrayView0<'_, A> {
69 unsafe { ArrayView::from_shape_ptr(Ix0(), x) }
70}
71
72/// Create a one-dimensional array view with elements borrowing `xs`.
73///
74/// ```
75/// use ndarray::aview1;
76///
77/// let data = [1.0; 1024];
78///
79/// // Create a 2D array view from borrowed data
80/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
81///
82/// assert_eq!(a2d.sum(), 1024.0);
83/// ```
84pub fn aview1<A>(xs: &[A]) -> ArrayView1<'_, A> {
85 ArrayView::from(xs)
86}
87
88/// Create a two-dimensional array view with elements borrowing `xs`.
89///
90/// **Panics** if the product of non-zero axis lengths overflows `isize`. (This
91/// can only occur when `V` is zero-sized.)
92pub fn aview2<A, V: FixedInitializer<Elem = A>>(xs: &[V]) -> ArrayView2<'_, A> {
93 let cols = V::len();
94 let rows = xs.len();
95 let dim = Ix2(rows, cols);
96 if size_of::<V>() == 0 {
97 dimension::size_of_shape_checked(&dim)
98 .expect("Product of non-zero axis lengths must not overflow isize.");
99 }
100 // `rows` is guaranteed to fit in `isize` because we've checked the ZST
101 // case and slices never contain > `isize::MAX` bytes. `cols` is guaranteed
102 // to fit in `isize` because `FixedInitializer` is not implemented for any
103 // array lengths > `isize::MAX`. `cols * rows` is guaranteed to fit in
104 // `isize` because we've checked the ZST case and slices never contain >
105 // `isize::MAX` bytes.
106 unsafe {
107 let data = slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows);
108 ArrayView::from_shape_ptr(dim, data.as_ptr())
109 }
110}
111
112/// Create a one-dimensional read-write array view with elements borrowing `xs`.
113///
114/// ```
115/// use ndarray::{aview_mut1, s};
116/// // Create an array view over some data, then slice it and modify it.
117/// let mut data = [0; 1024];
118/// {
119/// let mut a = aview_mut1(&mut data).into_shape((32, 32)).unwrap();
120/// a.slice_mut(s![.., ..;3]).fill(5);
121/// }
122/// assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
123/// ```
124pub fn aview_mut1<A>(xs: &mut [A]) -> ArrayViewMut1<'_, A> {
125 ArrayViewMut::from(xs)
126}
127
128/// Create a two-dimensional read-write array view with elements borrowing `xs`.
129///
130/// **Panics** if the product of non-zero axis lengths overflows `isize`. (This
131/// can only occur when `V` is zero-sized.)
132///
133/// # Example
134///
135/// ```
136/// use ndarray::aview_mut2;
137///
138/// // The inner (nested) array must be of length 1 to 16, but the outer
139/// // can be of any length.
140/// let mut data = [[0.; 2]; 128];
141/// {
142/// // Make a 128 x 2 mut array view then turn it into 2 x 128
143/// let mut a = aview_mut2(&mut data).reversed_axes();
144/// // Make the first row ones and second row minus ones.
145/// a.row_mut(0).fill(1.);
146/// a.row_mut(1).fill(-1.);
147/// }
148/// // look at the start of the result
149/// assert_eq!(&data[..3], [[1., -1.], [1., -1.], [1., -1.]]);
150/// ```
151pub fn aview_mut2<A, V: FixedInitializer<Elem = A>>(xs: &mut [V]) -> ArrayViewMut2<'_, A> {
152 let cols = V::len();
153 let rows = xs.len();
154 let dim = Ix2(rows, cols);
155 if size_of::<V>() == 0 {
156 dimension::size_of_shape_checked(&dim)
157 .expect("Product of non-zero axis lengths must not overflow isize.");
158 }
159 // `rows` is guaranteed to fit in `isize` because we've checked the ZST
160 // case and slices never contain > `isize::MAX` bytes. `cols` is guaranteed
161 // to fit in `isize` because `FixedInitializer` is not implemented for any
162 // array lengths > `isize::MAX`. `cols * rows` is guaranteed to fit in
163 // `isize` because we've checked the ZST case and slices never contain >
164 // `isize::MAX` bytes.
165 unsafe {
166 let data = slice::from_raw_parts_mut(xs.as_mut_ptr() as *mut A, cols * rows);
167 ArrayViewMut::from_shape_ptr(dim, data.as_mut_ptr())
168 }
169}
170
171/// Fixed-size array used for array initialization
172#[allow(clippy::missing_safety_doc)] // Should not be implemented downstream and to be deprecated.
173pub unsafe trait FixedInitializer {
174 type Elem;
175 fn as_init_slice(&self) -> &[Self::Elem];
176 fn len() -> usize;
177}
178
179macro_rules! impl_arr_init {
180 (__impl $n: expr) => (
181 unsafe impl<T> FixedInitializer for [T; $n] {
182 type Elem = T;
183 fn as_init_slice(&self) -> &[T] { self }
184 fn len() -> usize { $n }
185 }
186 );
187 () => ();
188 ($n: expr, $($m:expr,)*) => (
189 impl_arr_init!(__impl $n);
190 impl_arr_init!($($m,)*);
191 )
192
193}
194
195// For implementors: If you ever implement `FixedInitializer` for array lengths
196// > `isize::MAX` (e.g. once Rust adds const generics), you must update
197// `aview2` and `aview_mut2` to perform the necessary checks. In particular,
198// the assumption that `cols` can never exceed `isize::MAX` would be incorrect.
199// (Consider e.g. `let xs: &[[i32; ::std::usize::MAX]] = &[]`.)
200impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);
201
202/// Create a two-dimensional array with elements from `xs`.
203///
204/// ```
205/// use ndarray::arr2;
206///
207/// let a = arr2(&[[1, 2, 3],
208/// [4, 5, 6]]);
209/// assert!(
210/// a.shape() == [2, 3]
211/// );
212/// ```
213pub fn arr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> Array2<A>
214where
215 V: Clone,
216{
217 Array2::from(xs.to_vec())
218}
219
220impl<A, V> From<Vec<V>> for Array2<A>
221where
222 V: FixedInitializer<Elem = A>,
223{
224 /// Converts the `Vec` of arrays to an owned 2-D array.
225 ///
226 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
227 fn from(mut xs: Vec<V>) -> Self {
228 let dim = Ix2(xs.len(), V::len());
229 let ptr = xs.as_mut_ptr();
230 let cap = xs.capacity();
231 let expand_len = dimension::size_of_shape_checked(&dim)
232 .expect("Product of non-zero axis lengths must not overflow isize.");
233 forget(xs);
234 unsafe {
235 let v = if size_of::<A>() == 0 {
236 Vec::from_raw_parts(ptr as *mut A, expand_len, expand_len)
237 } else if V::len() == 0 {
238 Vec::new()
239 } else {
240 // Guaranteed not to overflow in this case since A is non-ZST
241 // and Vec never allocates more than isize bytes.
242 let expand_cap = cap * V::len();
243 Vec::from_raw_parts(ptr as *mut A, expand_len, expand_cap)
244 };
245 ArrayBase::from_shape_vec_unchecked(dim, v)
246 }
247 }
248}
249
250impl<A, V, U> From<Vec<V>> for Array3<A>
251where
252 V: FixedInitializer<Elem = U>,
253 U: FixedInitializer<Elem = A>,
254{
255 /// Converts the `Vec` of arrays to an owned 3-D array.
256 ///
257 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
258 fn from(mut xs: Vec<V>) -> Self {
259 let dim = Ix3(xs.len(), V::len(), U::len());
260 let ptr = xs.as_mut_ptr();
261 let cap = xs.capacity();
262 let expand_len = dimension::size_of_shape_checked(&dim)
263 .expect("Product of non-zero axis lengths must not overflow isize.");
264 forget(xs);
265 unsafe {
266 let v = if size_of::<A>() == 0 {
267 Vec::from_raw_parts(ptr as *mut A, expand_len, expand_len)
268 } else if V::len() == 0 || U::len() == 0 {
269 Vec::new()
270 } else {
271 // Guaranteed not to overflow in this case since A is non-ZST
272 // and Vec never allocates more than isize bytes.
273 let expand_cap = cap * V::len() * U::len();
274 Vec::from_raw_parts(ptr as *mut A, expand_len, expand_cap)
275 };
276 ArrayBase::from_shape_vec_unchecked(dim, v)
277 }
278 }
279}
280
281/// Create a two-dimensional array with elements from `xs`.
282///
283pub fn rcarr2<A: Clone, V: Clone + FixedInitializer<Elem = A>>(xs: &[V]) -> ArcArray2<A> {
284 arr2(xs).into_shared()
285}
286
287/// Create a three-dimensional array with elements from `xs`.
288///
289/// **Panics** if the slices are not all of the same length.
290///
291/// ```
292/// use ndarray::arr3;
293///
294/// let a = arr3(&[[[1, 2],
295/// [3, 4]],
296/// [[5, 6],
297/// [7, 8]],
298/// [[9, 0],
299/// [1, 2]]]);
300/// assert!(
301/// a.shape() == [3, 2, 2]
302/// );
303/// ```
304pub fn arr3<A: Clone, V: FixedInitializer<Elem = U>, U: FixedInitializer<Elem = A>>(
305 xs: &[V],
306) -> Array3<A>
307where
308 V: Clone,
309 U: Clone,
310{
311 Array3::from(xs.to_vec())
312}
313
314/// Create a three-dimensional array with elements from `xs`.
315pub fn rcarr3<A: Clone, V: FixedInitializer<Elem = U>, U: FixedInitializer<Elem = A>>(
316 xs: &[V],
317) -> ArcArray<A, Ix3>
318where
319 V: Clone,
320 U: Clone,
321{
322 arr3(xs).into_shared()
323}