From a2b6b30d75f4517806edb99d7a922e57e8e65792 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 1 Apr 2024 16:56:42 +0200 Subject: [PATCH] Add .into_raw_vec_with_offset() and deprecate .into_raw_vec() Provide a smoother transition by deprecating the old method and introducing a new one. Return usize for the offset instead of Option; I judge that the zero for an empty array is hard to misuse - indexing into the vector is bounds checked as usual, and zero is a natural value for no offset. --- examples/sort-axis.rs | 2 +- src/impl_owned_array.rs | 30 +++++++++++++++++++++--------- tests/array-construct.rs | 4 ++-- tests/array.rs | 9 ++++++--- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/examples/sort-axis.rs b/examples/sort-axis.rs index e86a45743..4da3a64d5 100644 --- a/examples/sort-axis.rs +++ b/examples/sort-axis.rs @@ -157,7 +157,7 @@ where D: Dimension }); debug_assert_eq!(result.len(), moved_elements); // forget the old elements but not the allocation - let mut old_storage = self.into_raw_vec().0; + let mut old_storage = self.into_raw_vec_and_offset().0; old_storage.set_len(0); // transfer ownership of the elements into the result diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs index 4774c1b7c..e63d6ea0f 100644 --- a/src/impl_owned_array.rs +++ b/src/impl_owned_array.rs @@ -77,7 +77,7 @@ where D: Dimension /// Return a vector of the elements in the array, in the way they are /// stored internally, and the index in the vector corresponding to the - /// logically first element of the array (or `None` if the array is empty). + /// logically first element of the array (or 0 if the array is empty). /// /// If the array is in standard memory layout, the logical element order /// of the array (`.iter()` order) and of the returned vector will be the same. @@ -92,15 +92,15 @@ where D: Dimension /// /// let shape = arr.shape().to_owned(); /// let strides = arr.strides().to_owned(); - /// let (v, offset) = arr.into_raw_vec(); + /// let (v, offset) = arr.into_raw_vec_and_offset(); /// /// assert_eq!(v, &[1., 2., 3., 4., 5., 6.]); - /// assert_eq!(offset, Some(2)); - /// assert_eq!(v[offset.unwrap()], 3.); + /// assert_eq!(offset, 2); + /// assert_eq!(v[offset], 3.); /// for row in 0..shape[0] { /// for col in 0..shape[1] { /// let index = ( - /// offset.unwrap() as isize + /// offset as isize /// + row as isize * strides[0] /// + col as isize * strides[1] /// ) as usize; @@ -124,13 +124,13 @@ where D: Dimension /// /// let shape = arr.shape().to_owned(); /// let strides = arr.strides().to_owned(); - /// let (v, offset) = arr.into_raw_vec(); + /// let (v, offset) = arr.into_raw_vec_and_offset(); /// /// assert_eq!(v, &[(), (), (), (), (), ()]); /// for row in 0..shape[0] { /// for col in 0..shape[1] { /// let index = ( - /// offset.unwrap() as isize + /// offset as isize /// + row as isize * strides[0] /// + col as isize * strides[1] /// ) as usize; @@ -138,11 +138,23 @@ where D: Dimension /// } /// } /// ``` - pub fn into_raw_vec(self) -> (Vec, Option) + pub fn into_raw_vec_and_offset(self) -> (Vec, usize) { - let offset = self.offset_from_alloc_to_logical_ptr(); + let offset = self.offset_from_alloc_to_logical_ptr().unwrap_or(0); (self.data.into_vec(), offset) } + + /// Return a vector of the elements in the array, in the way they are + /// stored internally. + /// + /// Depending on slicing and strides, the logically first element of the + /// array can be located at an offset. Because of this, prefer to use + /// `.into_raw_vec_and_offset()` instead. + #[deprecated(note = "Use .into_raw_vec_and_offset() instead")] + pub fn into_raw_vec(self) -> Vec + { + self.into_raw_vec_and_offset().0 + } } /// Methods specific to `Array2`. diff --git a/tests/array-construct.rs b/tests/array-construct.rs index a5fd00dc0..cc0d569bb 100644 --- a/tests/array-construct.rs +++ b/tests/array-construct.rs @@ -19,9 +19,9 @@ fn test_from_shape_fn() fn test_dimension_zero() { let a: Array2 = Array2::from(vec![[], [], []]); - assert_eq!(vec![0.; 0], a.into_raw_vec().0); + assert_eq!((vec![0.; 0], 0), a.into_raw_vec_and_offset()); let a: Array3 = Array3::from(vec![[[]], [[]], [[]]]); - assert_eq!(vec![0.; 0], a.into_raw_vec().0); + assert_eq!((vec![0.; 0], 0), a.into_raw_vec_and_offset()); } #[test] diff --git a/tests/array.rs b/tests/array.rs index 3c60aa616..c9286ecb0 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1157,7 +1157,10 @@ fn array0_into_scalar() // With this kind of setup, the `Array`'s pointer is not the same as the // underlying `Vec`'s pointer. let a: Array0 = array![4, 5, 6, 7].index_axis_move(Axis(0), 2); - assert_ne!(a.as_ptr(), a.into_raw_vec().0.as_ptr()); + let a_ptr = a.as_ptr(); + let (raw_vec, offset) = a.into_raw_vec_and_offset(); + assert_ne!(a_ptr, raw_vec.as_ptr()); + assert_eq!(offset, 2); // `.into_scalar()` should still work correctly. let a: Array0 = array![4, 5, 6, 7].index_axis_move(Axis(0), 2); assert_eq!(a.into_scalar(), 6); @@ -1173,7 +1176,7 @@ fn array_view0_into_scalar() // With this kind of setup, the `Array`'s pointer is not the same as the // underlying `Vec`'s pointer. let a: Array0 = array![4, 5, 6, 7].index_axis_move(Axis(0), 2); - assert_ne!(a.as_ptr(), a.into_raw_vec().0.as_ptr()); + assert_ne!(a.as_ptr(), a.into_raw_vec_and_offset().0.as_ptr()); // `.into_scalar()` should still work correctly. let a: Array0 = array![4, 5, 6, 7].index_axis_move(Axis(0), 2); assert_eq!(a.view().into_scalar(), &6); @@ -1189,7 +1192,7 @@ fn array_view_mut0_into_scalar() // With this kind of setup, the `Array`'s pointer is not the same as the // underlying `Vec`'s pointer. let a: Array0 = array![4, 5, 6, 7].index_axis_move(Axis(0), 2); - assert_ne!(a.as_ptr(), a.into_raw_vec().0.as_ptr()); + assert_ne!(a.as_ptr(), a.into_raw_vec_and_offset().0.as_ptr()); // `.into_scalar()` should still work correctly. let mut a: Array0 = array![4, 5, 6, 7].index_axis_move(Axis(0), 2); assert_eq!(a.view_mut().into_scalar(), &6);