ndarray/impl_constructors.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
9//! Constructor methods for ndarray
10//!
11//!
12
13#![allow(clippy::match_wild_err_arm)]
14use alloc::vec;
15#[cfg(not(feature = "std"))]
16use alloc::vec::Vec;
17#[cfg(feature = "std")]
18use num_traits::Float;
19use num_traits::{One, Zero};
20use std::mem;
21use std::mem::MaybeUninit;
22
23use crate::dimension::offset_from_low_addr_ptr_to_logical_ptr;
24use crate::dimension::{self, CanIndexCheckMode};
25use crate::error::{self, ShapeError};
26use crate::extension::nonnull::nonnull_from_vec_data;
27use crate::imp_prelude::*;
28use crate::indexes;
29use crate::indices;
30#[cfg(feature = "std")]
31use crate::iterators::to_vec;
32use crate::iterators::to_vec_mapped;
33use crate::iterators::TrustedIterator;
34use crate::StrideShape;
35#[cfg(feature = "std")]
36use crate::{geomspace, linspace, logspace};
37#[allow(unused_imports)]
38use rawpointer::PointerExt;
39
40/// # Constructor Methods for Owned Arrays
41///
42/// Note that the constructor methods apply to `Array` and `ArcArray`,
43/// the two array types that have owned storage.
44///
45/// ## Constructor methods for one-dimensional arrays.
46impl<S, A> ArrayBase<S, Ix1>
47where S: DataOwned<Elem = A>
48{
49 /// Create a one-dimensional array from a vector (no copying needed).
50 ///
51 /// **Panics** if the length is greater than `isize::MAX`.
52 ///
53 /// ```rust
54 /// use ndarray::Array;
55 ///
56 /// let array = Array::from_vec(vec![1., 2., 3., 4.]);
57 /// ```
58 pub fn from_vec(v: Vec<A>) -> Self
59 {
60 if mem::size_of::<A>() == 0 {
61 assert!(
62 v.len() <= isize::MAX as usize,
63 "Length must fit in `isize`.",
64 );
65 }
66 unsafe { Self::from_shape_vec_unchecked(v.len() as Ix, v) }
67 }
68
69 /// Create a one-dimensional array from an iterator or iterable.
70 ///
71 /// **Panics** if the length is greater than `isize::MAX`.
72 ///
73 /// ```rust
74 /// use ndarray::Array;
75 ///
76 /// let array = Array::from_iter(0..10);
77 /// ```
78 #[allow(clippy::should_implement_trait)]
79 pub fn from_iter<I: IntoIterator<Item = A>>(iterable: I) -> Self
80 {
81 Self::from_vec(iterable.into_iter().collect())
82 }
83
84 /// Create a one-dimensional array with `n` evenly spaced elements from
85 /// `start` to `end` (inclusive). `A` must be a floating point type.
86 ///
87 /// Note that if `start > end`, the first element will still be `start`,
88 /// and the following elements will be decreasing. This is different from
89 /// the behavior of `std::ops::RangeInclusive`, which interprets `start >
90 /// end` to mean that the range is empty.
91 ///
92 /// **Panics** if `n` is greater than `isize::MAX` or if converting `n - 1`
93 /// to type `A` fails.
94 ///
95 /// ```rust
96 /// use ndarray::{Array, arr1};
97 ///
98 /// let array = Array::linspace(0., 1., 5);
99 /// assert!(array == arr1(&[0.0, 0.25, 0.5, 0.75, 1.0]))
100 /// ```
101 #[cfg(feature = "std")]
102 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
103 pub fn linspace(start: A, end: A, n: usize) -> Self
104 where A: Float
105 {
106 Self::from(to_vec(linspace::linspace(start, end, n)))
107 }
108
109 /// Create a one-dimensional array with elements from `start` to `end`
110 /// (exclusive), incrementing by `step`. `A` must be a floating point type.
111 ///
112 /// **Panics** if the length is greater than `isize::MAX`.
113 ///
114 /// ```rust
115 /// use ndarray::{Array, arr1};
116 ///
117 /// let array = Array::range(0., 5., 1.);
118 /// assert!(array == arr1(&[0., 1., 2., 3., 4.]))
119 /// ```
120 #[cfg(feature = "std")]
121 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
122 pub fn range(start: A, end: A, step: A) -> Self
123 where A: Float
124 {
125 Self::from(to_vec(linspace::range(start, end, step)))
126 }
127
128 /// Create a one-dimensional array with `n` logarithmically spaced
129 /// elements, with the starting value being `base.powf(start)` and the
130 /// final one being `base.powf(end)`. `A` must be a floating point type.
131 ///
132 /// If `base` is negative, all values will be negative.
133 ///
134 /// **Panics** if `n` is greater than `isize::MAX` or if converting `n - 1`
135 /// to type `A` fails.
136 ///
137 /// ```rust
138 /// # #[cfg(feature = "approx")] {
139 /// use approx::assert_abs_diff_eq;
140 /// use ndarray::{Array, arr1};
141 ///
142 /// let array = Array::logspace(10.0, 0.0, 3.0, 4);
143 /// assert_abs_diff_eq!(array, arr1(&[1e0, 1e1, 1e2, 1e3]), epsilon = 1e-12);
144 ///
145 /// let array = Array::logspace(-10.0, 3.0, 0.0, 4);
146 /// assert_abs_diff_eq!(array, arr1(&[-1e3, -1e2, -1e1, -1e0]), epsilon = 1e-12);
147 /// # }
148 /// ```
149 #[cfg(feature = "std")]
150 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
151 pub fn logspace(base: A, start: A, end: A, n: usize) -> Self
152 where A: Float
153 {
154 Self::from(to_vec(logspace::logspace(base, start, end, n)))
155 }
156
157 /// Create a one-dimensional array with `n` geometrically spaced elements
158 /// from `start` to `end` (inclusive). `A` must be a floating point type.
159 ///
160 /// Returns `None` if `start` and `end` have different signs or if either
161 /// one is zero. Conceptually, this means that in order to obtain a `Some`
162 /// result, `end / start` must be positive.
163 ///
164 /// **Panics** if `n` is greater than `isize::MAX` or if converting `n - 1`
165 /// to type `A` fails.
166 ///
167 /// ```rust
168 /// # fn example() -> Option<()> {
169 /// # #[cfg(feature = "approx")] {
170 /// use approx::assert_abs_diff_eq;
171 /// use ndarray::{Array, arr1};
172 ///
173 /// let array = Array::geomspace(1e0, 1e3, 4)?;
174 /// assert_abs_diff_eq!(array, arr1(&[1e0, 1e1, 1e2, 1e3]), epsilon = 1e-11);
175 ///
176 /// let array = Array::geomspace(-1e3, -1e0, 4)?;
177 /// assert_abs_diff_eq!(array, arr1(&[-1e3, -1e2, -1e1, -1e0]), epsilon = 1e-11);
178 /// # }
179 /// # Some(())
180 /// # }
181 /// #
182 /// # example().unwrap();
183 /// ```
184 #[cfg(feature = "std")]
185 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
186 pub fn geomspace(start: A, end: A, n: usize) -> Option<Self>
187 where A: Float
188 {
189 Some(Self::from(to_vec(geomspace::geomspace(start, end, n)?)))
190 }
191}
192
193/// ## Constructor methods for two-dimensional arrays.
194impl<S, A> ArrayBase<S, Ix2>
195where S: DataOwned<Elem = A>
196{
197 /// Create an identity matrix of size `n` (square 2D array).
198 ///
199 /// **Panics** if `n * n` would overflow `isize`.
200 pub fn eye(n: Ix) -> Self
201 where
202 S: DataMut,
203 A: Clone + Zero + One,
204 {
205 let mut eye = Self::zeros((n, n));
206 for a_ii in eye.diag_mut() {
207 *a_ii = A::one();
208 }
209 eye
210 }
211
212 /// Create a 2D matrix from its diagonal
213 ///
214 /// **Panics** if `diag.len() * diag.len()` would overflow `isize`.
215 ///
216 /// ```rust
217 /// use ndarray::{Array2, arr1, arr2};
218 ///
219 /// let diag = arr1(&[1, 2]);
220 /// let array = Array2::from_diag(&diag);
221 /// assert_eq!(array, arr2(&[[1, 0], [0, 2]]));
222 /// ```
223 pub fn from_diag<S2>(diag: &ArrayBase<S2, Ix1>) -> Self
224 where
225 A: Clone + Zero,
226 S: DataMut,
227 S2: Data<Elem = A>,
228 {
229 let n = diag.len();
230 let mut arr = Self::zeros((n, n));
231 arr.diag_mut().assign(diag);
232 arr
233 }
234
235 /// Create a square 2D matrix of the specified size, with the specified
236 /// element along the diagonal and zeros elsewhere.
237 ///
238 /// **Panics** if `n * n` would overflow `isize`.
239 ///
240 /// ```rust
241 /// use ndarray::{array, Array2};
242 ///
243 /// let array = Array2::from_diag_elem(2, 5.);
244 /// assert_eq!(array, array![[5., 0.], [0., 5.]]);
245 /// ```
246 pub fn from_diag_elem(n: usize, elem: A) -> Self
247 where
248 S: DataMut,
249 A: Clone + Zero,
250 {
251 let mut eye = Self::zeros((n, n));
252 for a_ii in eye.diag_mut() {
253 *a_ii = elem.clone();
254 }
255 eye
256 }
257}
258
259#[cfg(not(debug_assertions))]
260#[allow(clippy::match_wild_err_arm)]
261macro_rules! size_of_shape_checked_unwrap {
262 ($dim:expr) => {
263 match dimension::size_of_shape_checked($dim) {
264 Ok(sz) => sz,
265 Err(_) => {
266 panic!("ndarray: Shape too large, product of non-zero axis lengths overflows isize")
267 }
268 }
269 };
270}
271
272#[cfg(debug_assertions)]
273macro_rules! size_of_shape_checked_unwrap {
274 ($dim:expr) => {
275 match dimension::size_of_shape_checked($dim) {
276 Ok(sz) => sz,
277 Err(_) => panic!(
278 "ndarray: Shape too large, product of non-zero axis lengths \
279 overflows isize in shape {:?}",
280 $dim
281 ),
282 }
283 };
284}
285
286/// ## Constructor methods for n-dimensional arrays.
287///
288/// The `shape` argument can be an integer or a tuple of integers to specify
289/// a static size. For example `10` makes a length 10 one-dimensional array
290/// (dimension type `Ix1`) and `(5, 6)` a 5 × 6 array (dimension type `Ix2`).
291///
292/// With the trait `ShapeBuilder` in scope, there is the method `.f()` to select
293/// column major (“f” order) memory layout instead of the default row major.
294/// For example `Array::zeros((5, 6).f())` makes a column major 5 × 6 array.
295///
296/// Use [`type@IxDyn`] for the shape to create an array with dynamic
297/// number of axes.
298///
299/// Finally, the few constructors that take a completely general
300/// `Into<StrideShape>` argument *optionally* support custom strides, for
301/// example a shape given like `(10, 2, 2).strides((1, 10, 20))` is valid.
302impl<S, A, D> ArrayBase<S, D>
303where
304 S: DataOwned<Elem = A>,
305 D: Dimension,
306{
307 /// Create an array with copies of `elem`, shape `shape`.
308 ///
309 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
310 ///
311 /// ```
312 /// use ndarray::{Array, arr3, ShapeBuilder};
313 ///
314 /// let a = Array::from_elem((2, 2, 2), 1.);
315 ///
316 /// assert!(
317 /// a == arr3(&[[[1., 1.],
318 /// [1., 1.]],
319 /// [[1., 1.],
320 /// [1., 1.]]])
321 /// );
322 /// assert!(a.strides() == &[4, 2, 1]);
323 ///
324 /// let b = Array::from_elem((2, 2, 2).f(), 1.);
325 /// assert!(b.strides() == &[1, 2, 4]);
326 /// ```
327 pub fn from_elem<Sh>(shape: Sh, elem: A) -> Self
328 where
329 A: Clone,
330 Sh: ShapeBuilder<Dim = D>,
331 {
332 let shape = shape.into_shape_with_order();
333 let size = size_of_shape_checked_unwrap!(&shape.dim);
334 let v = vec![elem; size];
335 unsafe { Self::from_shape_vec_unchecked(shape, v) }
336 }
337
338 /// Create an array with zeros, shape `shape`.
339 ///
340 /// The element type is inferred; to control it, you can either specify
341 /// type of the returned array or use turbofish syntax in the function call:
342 /// ```
343 /// use ndarray::{Array1, arr1};
344 ///
345 /// // Specify f32
346 /// let arr_f32: Array1<f32> = Array1::zeros(3);
347 /// assert_eq!(arr_f32, arr1(&[0_f32, 0.0, 0.0]));
348 ///
349 /// // Specify i64
350 /// let arr_i64 = Array1::<i64>::zeros(3);
351 /// assert_eq!(arr_i64, arr1(&[0_i64, 0, 0]));
352 /// ```
353 ///
354 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
355 pub fn zeros<Sh>(shape: Sh) -> Self
356 where
357 A: Clone + Zero,
358 Sh: ShapeBuilder<Dim = D>,
359 {
360 Self::from_elem(shape, A::zero())
361 }
362
363 /// Create an array with ones, shape `shape`.
364 ///
365 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
366 pub fn ones<Sh>(shape: Sh) -> Self
367 where
368 A: Clone + One,
369 Sh: ShapeBuilder<Dim = D>,
370 {
371 Self::from_elem(shape, A::one())
372 }
373
374 /// Create an array with default values, shape `shape`
375 ///
376 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
377 pub fn default<Sh>(shape: Sh) -> Self
378 where
379 A: Default,
380 Sh: ShapeBuilder<Dim = D>,
381 {
382 Self::from_shape_simple_fn(shape, A::default)
383 }
384
385 /// Create an array with values created by the function `f`.
386 ///
387 /// `f` is called with no argument, and it should return the element to
388 /// create. If the precise index of the element to create is needed,
389 /// use [`from_shape_fn`](ArrayBase::from_shape_fn) instead.
390 ///
391 /// This constructor can be useful if the element order is not important,
392 /// for example if they are identical or random.
393 ///
394 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
395 pub fn from_shape_simple_fn<Sh, F>(shape: Sh, mut f: F) -> Self
396 where
397 Sh: ShapeBuilder<Dim = D>,
398 F: FnMut() -> A,
399 {
400 let shape = shape.into_shape_with_order();
401 let len = size_of_shape_checked_unwrap!(&shape.dim);
402 let v = to_vec_mapped(0..len, move |_| f());
403 unsafe { Self::from_shape_vec_unchecked(shape, v) }
404 }
405
406 /// Create an array with values created by the function `f`.
407 ///
408 /// `f` is called with the index of the element to create; the elements are
409 /// visited in arbitrary order.
410 ///
411 /// **Panics** if the product of non-zero axis lengths overflows `isize`.
412 ///
413 /// ```
414 /// use ndarray::{Array, arr2};
415 ///
416 /// // Create a table of i × j (with i and j from 1 to 3)
417 /// let ij_table = Array::from_shape_fn((3, 3), |(i, j)| (1 + i) * (1 + j));
418 ///
419 /// assert_eq!(
420 /// ij_table,
421 /// arr2(&[[1, 2, 3],
422 /// [2, 4, 6],
423 /// [3, 6, 9]])
424 /// );
425 /// ```
426 pub fn from_shape_fn<Sh, F>(shape: Sh, f: F) -> Self
427 where
428 Sh: ShapeBuilder<Dim = D>,
429 F: FnMut(D::Pattern) -> A,
430 {
431 let shape = shape.into_shape_with_order();
432 let _ = size_of_shape_checked_unwrap!(&shape.dim);
433 if shape.is_c() {
434 let v = to_vec_mapped(indices(shape.dim.clone()).into_iter(), f);
435 unsafe { Self::from_shape_vec_unchecked(shape, v) }
436 } else {
437 let dim = shape.dim.clone();
438 let v = to_vec_mapped(indexes::indices_iter_f(dim), f);
439 unsafe { Self::from_shape_vec_unchecked(shape, v) }
440 }
441 }
442
443 /// Create an array with the given shape from a vector. (No cloning of
444 /// elements needed.)
445 ///
446 /// ----
447 ///
448 /// For a contiguous c- or f-order shape, the following applies:
449 ///
450 /// **Errors** if `shape` does not correspond to the number of elements in
451 /// `v` or if the shape/strides would result in overflowing `isize`.
452 ///
453 /// ----
454 ///
455 /// For custom strides, the following applies:
456 ///
457 /// **Errors** if strides and dimensions can point out of bounds of `v`, if
458 /// strides allow multiple indices to point to the same element, or if the
459 /// shape/strides would result in overflowing `isize`.
460 ///
461 /// ```
462 /// use ndarray::Array;
463 /// use ndarray::ShapeBuilder; // Needed for .strides() method
464 /// use ndarray::arr2;
465 ///
466 /// let a = Array::from_shape_vec((2, 2), vec![1., 2., 3., 4.]);
467 /// assert!(a.is_ok());
468 ///
469 /// let b = Array::from_shape_vec((2, 2).strides((1, 2)),
470 /// vec![1., 2., 3., 4.]).unwrap();
471 /// assert!(
472 /// b == arr2(&[[1., 3.],
473 /// [2., 4.]])
474 /// );
475 /// ```
476 pub fn from_shape_vec<Sh>(shape: Sh, v: Vec<A>) -> Result<Self, ShapeError>
477 where Sh: Into<StrideShape<D>>
478 {
479 // eliminate the type parameter Sh as soon as possible
480 Self::from_shape_vec_impl(shape.into(), v)
481 }
482
483 fn from_shape_vec_impl(shape: StrideShape<D>, v: Vec<A>) -> Result<Self, ShapeError>
484 {
485 let dim = shape.dim;
486 let is_custom = shape.strides.is_custom();
487 dimension::can_index_slice_with_strides(&v, &dim, &shape.strides, dimension::CanIndexCheckMode::OwnedMutable)?;
488 if !is_custom && dim.size() != v.len() {
489 return Err(error::incompatible_shapes(&Ix1(v.len()), &dim));
490 }
491 let strides = shape.strides.strides_for_dim(&dim);
492 unsafe { Ok(Self::from_vec_dim_stride_unchecked(dim, strides, v)) }
493 }
494
495 /// Creates an array from a vector and interpret it according to the
496 /// provided shape and strides. (No cloning of elements needed.)
497 ///
498 /// # Safety
499 ///
500 /// The caller must ensure that the following conditions are met:
501 ///
502 /// 1. The ndim of `dim` and `strides` must be the same.
503 ///
504 /// 2. The product of non-zero axis lengths must not exceed `isize::MAX`.
505 ///
506 /// 3. For axes with length > 1, the pointer cannot move outside the
507 /// slice.
508 ///
509 /// 4. If the array will be empty (any axes are zero-length), the
510 /// difference between the least address and greatest address accessible
511 /// by moving along all axes must be ≤ `v.len()`.
512 ///
513 /// If the array will not be empty, the difference between the least
514 /// address and greatest address accessible by moving along all axes
515 /// must be < `v.len()`.
516 ///
517 /// 5. The strides must not allow any element to be referenced by two different
518 /// indices.
519 pub unsafe fn from_shape_vec_unchecked<Sh>(shape: Sh, v: Vec<A>) -> Self
520 where Sh: Into<StrideShape<D>>
521 {
522 let shape = shape.into();
523 let dim = shape.dim;
524 let strides = shape.strides.strides_for_dim(&dim);
525 Self::from_vec_dim_stride_unchecked(dim, strides, v)
526 }
527
528 unsafe fn from_vec_dim_stride_unchecked(dim: D, strides: D, mut v: Vec<A>) -> Self
529 {
530 // debug check for issues that indicates wrong use of this constructor
531 debug_assert!(dimension::can_index_slice(&v, &dim, &strides, CanIndexCheckMode::OwnedMutable).is_ok());
532
533 let ptr = nonnull_from_vec_data(&mut v).add(offset_from_low_addr_ptr_to_logical_ptr(&dim, &strides));
534 ArrayBase::from_data_ptr(DataOwned::new(v), ptr).with_strides_dim(strides, dim)
535 }
536
537 /// Creates an array from an iterator, mapped by `map` and interpret it according to the
538 /// provided shape and strides.
539 ///
540 /// # Safety
541 ///
542 /// See from_shape_vec_unchecked
543 pub(crate) unsafe fn from_shape_trusted_iter_unchecked<Sh, I, F>(shape: Sh, iter: I, map: F) -> Self
544 where
545 Sh: Into<StrideShape<D>>,
546 I: TrustedIterator + ExactSizeIterator,
547 F: FnMut(I::Item) -> A,
548 {
549 let shape = shape.into();
550 let dim = shape.dim;
551 let strides = shape.strides.strides_for_dim(&dim);
552 let v = to_vec_mapped(iter, map);
553 Self::from_vec_dim_stride_unchecked(dim, strides, v)
554 }
555
556 /// Create an array with uninitialized elements, shape `shape`.
557 ///
558 /// The uninitialized elements of type `A` are represented by the type `MaybeUninit<A>`,
559 /// an easier way to handle uninit values correctly.
560 ///
561 /// Only *when* the array is completely initialized with valid elements, can it be
562 /// converted to an array of `A` elements using [`.assume_init()`].
563 ///
564 /// **Panics** if the number of elements in `shape` would overflow isize.
565 ///
566 /// ### Safety
567 ///
568 /// The whole of the array must be initialized before it is converted
569 /// using [`.assume_init()`] or otherwise traversed/read with the element type `A`.
570 ///
571 /// ### Examples
572 ///
573 /// It is possible to assign individual values through `*elt = MaybeUninit::new(value)`
574 /// and so on.
575 ///
576 /// [`.assume_init()`]: ArrayBase::assume_init
577 ///
578 /// ```
579 /// use ndarray::{s, Array2};
580 ///
581 /// // Example Task: Let's create a column shifted copy of the input
582 ///
583 /// fn shift_by_two(a: &Array2<f32>) -> Array2<f32> {
584 /// // create an uninitialized array
585 /// let mut b = Array2::uninit(a.dim());
586 ///
587 /// // two first columns in b are two last in a
588 /// // rest of columns in b are the initial columns in a
589 ///
590 /// a.slice(s![.., -2..]).assign_to(b.slice_mut(s![.., ..2]));
591 /// a.slice(s![.., 2..]).assign_to(b.slice_mut(s![.., ..-2]));
592 ///
593 /// // Now we can promise that `b` is safe to use with all operations
594 /// unsafe {
595 /// b.assume_init()
596 /// }
597 /// }
598 ///
599 /// # let _ = shift_by_two;
600 /// ```
601 pub fn uninit<Sh>(shape: Sh) -> ArrayBase<S::MaybeUninit, D>
602 where Sh: ShapeBuilder<Dim = D>
603 {
604 unsafe {
605 let shape = shape.into_shape_with_order();
606 let size = size_of_shape_checked_unwrap!(&shape.dim);
607 let mut v = Vec::with_capacity(size);
608 v.set_len(size);
609 ArrayBase::from_shape_vec_unchecked(shape, v)
610 }
611 }
612
613 /// Create an array with uninitialized elements, shape `shape`.
614 ///
615 /// The uninitialized elements of type `A` are represented by the type `MaybeUninit<A>`,
616 /// an easier way to handle uninit values correctly.
617 ///
618 /// The `builder` closure gets unshared access to the array through a view and can use it to
619 /// modify the array before it is returned. This allows initializing the array for any owned
620 /// array type (avoiding clone requirements for copy-on-write, because the array is unshared
621 /// when initially created).
622 ///
623 /// Only *when* the array is completely initialized with valid elements, can it be
624 /// converted to an array of `A` elements using [`.assume_init()`].
625 ///
626 /// **Panics** if the number of elements in `shape` would overflow isize.
627 ///
628 /// ### Safety
629 ///
630 /// The whole of the array must be initialized before it is converted
631 /// using [`.assume_init()`] or otherwise traversed/read with the element type `A`.
632 ///
633 /// [`.assume_init()`]: ArrayBase::assume_init
634 pub fn build_uninit<Sh, F>(shape: Sh, builder: F) -> ArrayBase<S::MaybeUninit, D>
635 where
636 Sh: ShapeBuilder<Dim = D>,
637 F: FnOnce(ArrayViewMut<MaybeUninit<A>, D>),
638 {
639 let mut array = Self::uninit(shape);
640 // Safe because: the array is unshared here
641 unsafe {
642 builder(array.raw_view_mut_unchecked().deref_into_view_mut());
643 }
644 array
645 }
646}