Repository: bluss/rust-ndarray
Pull request #282 (2017-03-24 15:39:57)

ENH: Add constructor Array::uninitialized
- Also fix a bug noticed in Array::default not checking the size properly.


Patch:
diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs
index fd6e93d3..9f0cff6c 100644
--- a/src/impl_constructors.rs
+++ b/src/impl_constructors.rs
@@ -170,7 +170,8 @@ impl<S, A, D> ArrayBase<S, D>
               Sh: ShapeBuilder<Dim=D>,
     {
         let shape = shape.into_shape();
-        let v = to_vec((0..shape.dim.size()).map(|_| A::default()));
+        let size = size_checked_unwrap!(shape.dim);
+        let v = to_vec((0..size).map(|_| A::default()));
         unsafe { Self::from_shape_vec_unchecked(shape, v) }
     }
 
@@ -281,4 +282,43 @@ impl<S, A, D> ArrayBase<S, D>
         }
     }
 
+    /// Create an array with uninitalized elements, shape `shape`.
+    ///
+    /// **Panics** if the number of elements in `shape` would overflow usize.
+    ///
+    /// ## Safety
+    ///
+    /// Accessing uninitalized values is undefined behaviour. You must
+    /// overwrite *all* the elements in the array after it is created; for
+    /// example using the methods `.fill()` or `.assign()`.
+    ///
+    /// The contents of the array is indeterminate before initialization and it
+    /// is an error to perform operations that use the previous values. For
+    /// example it would not be legal to use `a += 1.;` on such an array.
+    ///
+    /// This constructor is limited to elements where `A: Copy` (no destructors)
+    /// to avoid users shooting themselves too hard in the foot; it is not
+    /// a problem to drop an array created with this method even before elements
+    /// are initialized. (Note that constructors `from_shape_vec` and
+    /// `from_shape_vec_unchecked` allow the user yet more control).
+    ///
+    /// ```
+    /// use ndarray::Array;
+    ///
+    /// let mut a = unsafe { Array::uninitialized((4, 5)) };
+    /// a.fill(1.);
+    ///
+    /// // `a` is safe to use with all operations at this point
+    /// ```
+    pub unsafe fn uninitialized<Sh>(shape: Sh) -> Self
+        where A: Copy,
+              Sh: ShapeBuilder<Dim=D>,
+    {
+        let shape = shape.into_shape();
+        let size = size_checked_unwrap!(shape.dim);
+        let mut v = Vec::with_capacity(size);
+        v.set_len(size);
+        Self::from_shape_vec_unchecked(shape, v)
+    }
+
 }


Test patch:
diff --git a/tests/array-construct.rs b/tests/array-construct.rs
index ae9985d6..11637fa6 100644
--- a/tests/array-construct.rs
+++ b/tests/array-construct.rs
@@ -29,3 +29,54 @@ fn test_rc_into_owned() {
     // test that they are unshared
     assert!(!a.all_close(&c, 0.01));
 }
+
+#[test]
+fn test_uninit() {
+    unsafe {
+        let mut a = Array::<f32, _>::uninitialized((3, 4).f());
+        assert_eq!(a.dim(), (3, 4));
+        assert_eq!(a.strides(), &[1, 3]);
+        let b = Array::<f32, _>::linspace(0., 25., a.len()).into_shape(a.dim()).unwrap();
+        a.assign(&b);
+        assert_eq!(&a, &b);
+        assert_eq!(a.t(), b.t());
+    }
+}
+
+#[test]
+fn deny_wraparound_from_vec() {
+    let five = vec![0; 5];
+    let five_large = Array::from_shape_vec((3, 7, 29, 36760123, 823996703), five.clone());
+    assert!(five_large.is_err());
+    let six = Array::from_shape_vec(6, five.clone());
+    assert!(six.is_err());
+}
+
+#[should_panic]
+#[test]
+fn deny_wraparound_zeros() {
+    //2^64 + 5 = 18446744073709551621 = 3×7×29×36760123×823996703  (5 distinct prime factors)
+    let _five_large = Array::<f32, _>::zeros((3, 7, 29, 36760123, 823996703));
+}
+
+#[should_panic]
+#[test]
+fn deny_wraparound_reshape() {
+    //2^64 + 5 = 18446744073709551621 = 3×7×29×36760123×823996703  (5 distinct prime factors)
+    let five = Array::<f32, _>::zeros(5);
+    let _five_large = five.into_shape((3, 7, 29, 36760123, 823996703)).unwrap();
+}
+
+#[should_panic]
+#[test]
+fn deny_wraparound_default() {
+    let _five_large = Array::<f32, _>::default((3, 7, 29, 36760123, 823996703));
+}
+
+#[should_panic]
+#[test]
+fn deny_wraparound_uninit() {
+    unsafe {
+        let _five_large = Array::<f32, _>::uninitialized((3, 7, 29, 36760123, 823996703));
+    }
+}
diff --git a/tests/array.rs b/tests/array.rs
index ab4d1c84..d93f301f 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -825,30 +825,6 @@ fn scalar_ops() {
     assert_eq!(3 << &one , 6 * &one);
 }
 
-#[test]
-fn deny_wraparound_from_vec() {
-    let five = vec![0; 5];
-    let five_large = Array::from_shape_vec((3, 7, 29, 36760123, 823996703), five.clone());
-    assert!(five_large.is_err());
-    let six = Array::from_shape_vec(6, five.clone());
-    assert!(six.is_err());
-}
-
-#[should_panic]
-#[test]
-fn deny_wraparound_zeros() {
-    //2^64 + 5 = 18446744073709551621 = 3×7×29×36760123×823996703  (5 distinct prime factors)
-    let _five_large = Array::<f32, _>::zeros((3, 7, 29, 36760123, 823996703));
-}
-
-#[should_panic]
-#[test]
-fn deny_wraparound_reshape() {
-    //2^64 + 5 = 18446744073709551621 = 3×7×29×36760123×823996703  (5 distinct prime factors)
-    let five = Array::<f32, _>::zeros(5);
-    let _five_large = five.into_shape((3, 7, 29, 36760123, 823996703)).unwrap();
-}
-
 #[test]
 fn split_at() {
     let mut a = arr2(&[[1., 2.], [3., 4.]]);