From 03b1fab712090e24dbc2eccadaa5bf78ab433819 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 16:59:25 +0100 Subject: [PATCH 1/7] Convert impl_views to a folder module --- src/{impl_views.rs => impl_views/mod.rs} | 88 ++++++++++++------------ 1 file changed, 44 insertions(+), 44 deletions(-) rename src/{impl_views.rs => impl_views/mod.rs} (95%) diff --git a/src/impl_views.rs b/src/impl_views/mod.rs similarity index 95% rename from src/impl_views.rs rename to src/impl_views/mod.rs index b679a7146..99e875c79 100644 --- a/src/impl_views.rs +++ b/src/impl_views/mod.rs @@ -18,10 +18,10 @@ use crate::{Baseiter, ElementsBase, ElementsBaseMut, Iter, IterMut}; use crate::iter::{self, AxisIter, AxisIterMut}; -/// Methods for read-only array views. +/// Methods for read-only array impl_views. impl<'a, A, D> ArrayView<'a, A, D> -where - D: Dimension, + where + D: Dimension, { /// Create a read-only array view borrowing its data from a slice. /// @@ -48,8 +48,8 @@ where /// assert!(a.strides() == &[1, 4, 2]); /// ``` pub fn from_shape(shape: Sh, xs: &'a [A]) -> Result - where - Sh: Into>, + where + Sh: Into>, { // eliminate the type parameter Sh as soon as possible Self::from_shape_impl(shape.into(), xs) @@ -104,8 +104,8 @@ where /// /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset pub unsafe fn from_shape_ptr(shape: Sh, ptr: *const A) -> Self - where - Sh: Into>, + where + Sh: Into>, { RawArrayView::from_shape_ptr(shape, ptr).deref_into_view() } @@ -113,8 +113,8 @@ where /// Convert the view into an `ArrayView<'b, A, D>` where `'b` is a lifetime /// outlived by `'a'`. pub fn reborrow<'b>(self) -> ArrayView<'b, A, D> - where - 'a: 'b, + where + 'a: 'b, { unsafe { ArrayView::new_(self.as_ptr(), self.dim, self.strides) } } @@ -151,7 +151,7 @@ where /// /// **Example 1**: Split `a` along the first axis, in this case the rows, at /// index 1.
- /// This produces views v1 and v2 of shapes 1 × 4 and 2 × 4: + /// This produces impl_views v1 and v2 of shapes 1 × 4 and 2 × 4: /// /// ```rust /// # use ndarray::prelude::*; @@ -172,7 +172,7 @@ where /// /// **Example 2**: Split `a` along the second axis, in this case the /// columns, at index 2.
- /// This produces views u1 and u2 of shapes 3 × 2 and 3 × 2: + /// This produces impl_views u1 and u2 of shapes 3 × 2 and 3 × 2: /// /// ```rust /// # use ndarray::prelude::*; @@ -227,7 +227,7 @@ where } } -/// Extra indexing methods for array views +/// Extra indexing methods for array impl_views /// /// These methods are very similar to regular indexing or calling of the /// `get`/`get_mut` methods that we can use on any array or array view. The @@ -240,7 +240,7 @@ where /// /// For `ArrayViewMut` to obey the borrowing rules we have to consume the /// view if we call any of these methods. (The equivalent of reborrow is -/// `.view_mut()` for read-write array views, but if you can use that, +/// `.view_mut()` for read-write array impl_views, but if you can use that, /// then the regular indexing / `get_mut` should suffice, too.) /// /// ``` @@ -274,7 +274,7 @@ pub trait IndexLonger { /// `Index` trait. /// /// See also [the `get` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.get /// @@ -288,7 +288,7 @@ pub trait IndexLonger { /// `Index` trait. /// /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.get /// [2]: struct.ArrayBase.html#method.get_mut @@ -302,7 +302,7 @@ pub trait IndexLonger { /// view); which we can't do for general arrays. /// /// See also [the `uget` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.uget /// @@ -311,9 +311,9 @@ pub trait IndexLonger { } impl<'a, 'b, I, A, D> IndexLonger for &'b ArrayView<'a, A, D> -where - I: NdIndex, - D: Dimension, + where + I: NdIndex, + D: Dimension, { type Output = &'a A; @@ -324,7 +324,7 @@ where /// `Index` trait. /// /// See also [the `get` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.get /// @@ -344,7 +344,7 @@ where /// view); which we can't do for general arrays. /// /// See also [the `uget` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.uget /// @@ -355,10 +355,10 @@ where } } -/// Methods for read-write array views. +/// Methods for read-write array impl_views. impl<'a, A, D> ArrayViewMut<'a, A, D> -where - D: Dimension, + where + D: Dimension, { /// Create a read-write array view borrowing its data from a slice. /// @@ -386,8 +386,8 @@ where /// assert!(a.strides() == &[1, 4, 2]); /// ``` pub fn from_shape(shape: Sh, xs: &'a mut [A]) -> Result - where - Sh: Into>, + where + Sh: Into>, { // eliminate the type parameter Sh as soon as possible Self::from_shape_impl(shape.into(), xs) @@ -442,8 +442,8 @@ where /// /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset pub unsafe fn from_shape_ptr(shape: Sh, ptr: *mut A) -> Self - where - Sh: Into>, + where + Sh: Into>, { RawArrayViewMut::from_shape_ptr(shape, ptr).deref_into_view_mut() } @@ -451,8 +451,8 @@ where /// Convert the view into an `ArrayViewMut<'b, A, D>` where `'b` is a lifetime /// outlived by `'a'`. pub fn reborrow<'b>(mut self) -> ArrayViewMut<'b, A, D> - where - 'a: 'b, + where + 'a: 'b, { unsafe { ArrayViewMut::new_(self.as_mut_ptr(), self.dim, self.strides) } } @@ -476,9 +476,9 @@ where } impl<'a, I, A, D> IndexLonger for ArrayViewMut<'a, A, D> -where - I: NdIndex, - D: Dimension, + where + I: NdIndex, + D: Dimension, { type Output = &'a mut A; @@ -489,7 +489,7 @@ where /// not in the `Index` trait. /// /// See also [the `get_mut` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.get_mut /// @@ -508,7 +508,7 @@ where /// checked access. /// /// See also [the `get_mut` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.get_mut /// @@ -526,7 +526,7 @@ where /// boundary check. /// /// See also [the `uget_mut` method][1] which works for all arrays and array - /// views. + /// impl_views. /// /// [1]: struct.ArrayBase.html#method.uget_mut /// @@ -541,8 +541,8 @@ where /// Private array view methods impl<'a, A, D> ArrayView<'a, A, D> -where - D: Dimension, + where + D: Dimension, { /// Create a new `ArrayView` /// @@ -575,16 +575,16 @@ where #[doc(hidden)] // not official #[deprecated(note = "This method will be replaced.")] pub fn into_outer_iter(self) -> iter::AxisIter<'a, A, D::Smaller> - where - D: RemoveAxis, + where + D: RemoveAxis, { AxisIter::new(self, Axis(0)) } } impl<'a, A, D> ArrayViewMut<'a, A, D> -where - D: Dimension, + where + D: Dimension, { /// Create a new `ArrayView` /// @@ -640,8 +640,8 @@ where #[doc(hidden)] // not official #[deprecated(note = "This method will be replaced.")] pub fn into_outer_iter(self) -> iter::AxisIterMut<'a, A, D::Smaller> - where - D: RemoveAxis, + where + D: RemoveAxis, { AxisIterMut::new(self, Axis(0)) } From eb2ceb2b51d0be58ec29658bdad9aa072c7a2681 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 17:02:08 +0100 Subject: [PATCH 2/7] Fix docs --- src/impl_views/mod.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/impl_views/mod.rs b/src/impl_views/mod.rs index 99e875c79..220c6b28d 100644 --- a/src/impl_views/mod.rs +++ b/src/impl_views/mod.rs @@ -18,7 +18,7 @@ use crate::{Baseiter, ElementsBase, ElementsBaseMut, Iter, IterMut}; use crate::iter::{self, AxisIter, AxisIterMut}; -/// Methods for read-only array impl_views. +/// Methods for read-only array views. impl<'a, A, D> ArrayView<'a, A, D> where D: Dimension, @@ -151,7 +151,7 @@ impl<'a, A, D> ArrayView<'a, A, D> /// /// **Example 1**: Split `a` along the first axis, in this case the rows, at /// index 1.
- /// This produces impl_views v1 and v2 of shapes 1 × 4 and 2 × 4: + /// This produces views v1 and v2 of shapes 1 × 4 and 2 × 4: /// /// ```rust /// # use ndarray::prelude::*; @@ -172,7 +172,7 @@ impl<'a, A, D> ArrayView<'a, A, D> /// /// **Example 2**: Split `a` along the second axis, in this case the /// columns, at index 2.
- /// This produces impl_views u1 and u2 of shapes 3 × 2 and 3 × 2: + /// This produces views u1 and u2 of shapes 3 × 2 and 3 × 2: /// /// ```rust /// # use ndarray::prelude::*; @@ -227,7 +227,7 @@ impl<'a, A, D> ArrayView<'a, A, D> } } -/// Extra indexing methods for array impl_views +/// Extra indexing methods for array views /// /// These methods are very similar to regular indexing or calling of the /// `get`/`get_mut` methods that we can use on any array or array view. The @@ -240,7 +240,7 @@ impl<'a, A, D> ArrayView<'a, A, D> /// /// For `ArrayViewMut` to obey the borrowing rules we have to consume the /// view if we call any of these methods. (The equivalent of reborrow is -/// `.view_mut()` for read-write array impl_views, but if you can use that, +/// `.view_mut()` for read-write array views, but if you can use that, /// then the regular indexing / `get_mut` should suffice, too.) /// /// ``` @@ -274,7 +274,7 @@ pub trait IndexLonger { /// `Index` trait. /// /// See also [the `get` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.get /// @@ -288,7 +288,7 @@ pub trait IndexLonger { /// `Index` trait. /// /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.get /// [2]: struct.ArrayBase.html#method.get_mut @@ -302,7 +302,7 @@ pub trait IndexLonger { /// view); which we can't do for general arrays. /// /// See also [the `uget` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.uget /// @@ -324,7 +324,7 @@ impl<'a, 'b, I, A, D> IndexLonger for &'b ArrayView<'a, A, D> /// `Index` trait. /// /// See also [the `get` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.get /// @@ -344,7 +344,7 @@ impl<'a, 'b, I, A, D> IndexLonger for &'b ArrayView<'a, A, D> /// view); which we can't do for general arrays. /// /// See also [the `uget` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.uget /// @@ -355,7 +355,7 @@ impl<'a, 'b, I, A, D> IndexLonger for &'b ArrayView<'a, A, D> } } -/// Methods for read-write array impl_views. +/// Methods for read-write array views. impl<'a, A, D> ArrayViewMut<'a, A, D> where D: Dimension, @@ -489,7 +489,7 @@ impl<'a, I, A, D> IndexLonger for ArrayViewMut<'a, A, D> /// not in the `Index` trait. /// /// See also [the `get_mut` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.get_mut /// @@ -508,7 +508,7 @@ impl<'a, I, A, D> IndexLonger for ArrayViewMut<'a, A, D> /// checked access. /// /// See also [the `get_mut` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.get_mut /// @@ -526,7 +526,7 @@ impl<'a, I, A, D> IndexLonger for ArrayViewMut<'a, A, D> /// boundary check. /// /// See also [the `uget_mut` method][1] which works for all arrays and array - /// impl_views. + /// views. /// /// [1]: struct.ArrayBase.html#method.uget_mut /// From 4cf66c87b1744a58ff2483f3e3165e7d52301272 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 17:19:02 +0100 Subject: [PATCH 3/7] Split into sub-module with a semantic/functionality meaning --- src/impl_views/constructors.rs | 250 +++++++++++++ src/impl_views/conversions.rs | 146 ++++++++ src/impl_views/indexing.rs | 203 ++++++++++ src/impl_views/mod.rs | 657 +-------------------------------- src/impl_views/splitting.rs | 112 ++++++ 5 files changed, 720 insertions(+), 648 deletions(-) create mode 100644 src/impl_views/constructors.rs create mode 100644 src/impl_views/conversions.rs create mode 100644 src/impl_views/indexing.rs create mode 100644 src/impl_views/splitting.rs diff --git a/src/impl_views/constructors.rs b/src/impl_views/constructors.rs new file mode 100644 index 000000000..aec155492 --- /dev/null +++ b/src/impl_views/constructors.rs @@ -0,0 +1,250 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::dimension; +use crate::error::ShapeError; +use crate::imp_prelude::*; +use crate::{is_aligned, StrideShape}; + +/// Methods for read-only array views. +impl<'a, A, D> ArrayView<'a, A, D> +where + D: Dimension, +{ + /// Create a read-only array view borrowing its data from a slice. + /// + /// Checks whether `shape` are compatible with the slice's + /// length, returning an `Err` if not compatible. + /// + /// ``` + /// use ndarray::ArrayView; + /// use ndarray::arr3; + /// use ndarray::ShapeBuilder; + /// + /// let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + /// let a = ArrayView::from_shape((2, 3, 2).strides((1, 4, 2)), + /// &s).unwrap(); + /// + /// assert!( + /// a == arr3(&[[[0, 2], + /// [4, 6], + /// [8, 10]], + /// [[1, 3], + /// [5, 7], + /// [9, 11]]]) + /// ); + /// assert!(a.strides() == &[1, 4, 2]); + /// ``` + pub fn from_shape(shape: Sh, xs: &'a [A]) -> Result + where + Sh: Into>, + { + // eliminate the type parameter Sh as soon as possible + Self::from_shape_impl(shape.into(), xs) + } + + fn from_shape_impl(shape: StrideShape, xs: &'a [A]) -> Result { + let dim = shape.dim; + let strides = shape.strides; + if shape.custom { + dimension::can_index_slice(xs, &dim, &strides)?; + } else { + dimension::can_index_slice_not_custom::(xs, &dim)?; + } + unsafe { Ok(Self::new_(xs.as_ptr(), dim, strides)) } + } + + /// Create an `ArrayView` from shape information and a raw pointer to + /// the elements. + /// + /// Unsafe because caller is responsible for ensuring all of the following: + /// + /// * The elements seen by moving `ptr` according to the shape and strides + /// must live at least as long as `'a` and must not be not mutably + /// aliased for the duration of `'a`. + /// + /// * `ptr` must be non-null and aligned, and it must be safe to + /// [`.offset()`] `ptr` by zero. + /// + /// * It must be safe to [`.offset()`] the pointer repeatedly along all + /// axes and calculate the `count`s for the `.offset()` calls without + /// overflow, even if the array is empty or the elements are zero-sized. + /// + /// In other words, + /// + /// * All possible pointers generated by moving along all axes must be in + /// bounds or one byte past the end of a single allocation with element + /// type `A`. The only exceptions are if the array is empty or the element + /// type is zero-sized. In these cases, `ptr` may be dangling, but it must + /// still be safe to [`.offset()`] the pointer along the axes. + /// + /// * The offset in units of bytes between the least address and greatest + /// address by moving along all axes must not exceed `isize::MAX`. This + /// constraint prevents the computed offset, in bytes, from overflowing + /// `isize` regardless of the starting point due to past offsets. + /// + /// * The offset in units of `A` between the least address and greatest + /// address by moving along all axes must not exceed `isize::MAX`. This + /// constraint prevents overflow when calculating the `count` parameter to + /// [`.offset()`] regardless of the starting point due to past offsets. + /// + /// * The product of non-zero axis lengths must not exceed `isize::MAX`. + /// + /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset + pub unsafe fn from_shape_ptr(shape: Sh, ptr: *const A) -> Self + where + Sh: Into>, + { + RawArrayView::from_shape_ptr(shape, ptr).deref_into_view() + } +} + +/// Methods for read-write array views. +impl<'a, A, D> ArrayViewMut<'a, A, D> +where + D: Dimension, +{ + /// Create a read-write array view borrowing its data from a slice. + /// + /// Checks whether `dim` and `strides` are compatible with the slice's + /// length, returning an `Err` if not compatible. + /// + /// ``` + /// use ndarray::ArrayViewMut; + /// use ndarray::arr3; + /// use ndarray::ShapeBuilder; + /// + /// let mut s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + /// let mut a = ArrayViewMut::from_shape((2, 3, 2).strides((1, 4, 2)), + /// &mut s).unwrap(); + /// + /// a[[0, 0, 0]] = 1; + /// assert!( + /// a == arr3(&[[[1, 2], + /// [4, 6], + /// [8, 10]], + /// [[1, 3], + /// [5, 7], + /// [9, 11]]]) + /// ); + /// assert!(a.strides() == &[1, 4, 2]); + /// ``` + pub fn from_shape(shape: Sh, xs: &'a mut [A]) -> Result + where + Sh: Into>, + { + // eliminate the type parameter Sh as soon as possible + Self::from_shape_impl(shape.into(), xs) + } + + fn from_shape_impl(shape: StrideShape, xs: &'a mut [A]) -> Result { + let dim = shape.dim; + let strides = shape.strides; + if shape.custom { + dimension::can_index_slice(xs, &dim, &strides)?; + } else { + dimension::can_index_slice_not_custom::(xs, &dim)?; + } + unsafe { Ok(Self::new_(xs.as_mut_ptr(), dim, strides)) } + } + + /// Create an `ArrayViewMut` from shape information and a + /// raw pointer to the elements. + /// + /// Unsafe because caller is responsible for ensuring all of the following: + /// + /// * The elements seen by moving `ptr` according to the shape and strides + /// must live at least as long as `'a` and must not be aliased for the + /// duration of `'a`. + /// + /// * `ptr` must be non-null and aligned, and it must be safe to + /// [`.offset()`] `ptr` by zero. + /// + /// * It must be safe to [`.offset()`] the pointer repeatedly along all + /// axes and calculate the `count`s for the `.offset()` calls without + /// overflow, even if the array is empty or the elements are zero-sized. + /// + /// In other words, + /// + /// * All possible pointers generated by moving along all axes must be in + /// bounds or one byte past the end of a single allocation with element + /// type `A`. The only exceptions are if the array is empty or the element + /// type is zero-sized. In these cases, `ptr` may be dangling, but it must + /// still be safe to [`.offset()`] the pointer along the axes. + /// + /// * The offset in units of bytes between the least address and greatest + /// address by moving along all axes must not exceed `isize::MAX`. This + /// constraint prevents the computed offset, in bytes, from overflowing + /// `isize` regardless of the starting point due to past offsets. + /// + /// * The offset in units of `A` between the least address and greatest + /// address by moving along all axes must not exceed `isize::MAX`. This + /// constraint prevents overflow when calculating the `count` parameter to + /// [`.offset()`] regardless of the starting point due to past offsets. + /// + /// * The product of non-zero axis lengths must not exceed `isize::MAX`. + /// + /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset + pub unsafe fn from_shape_ptr(shape: Sh, ptr: *mut A) -> Self + where + Sh: Into>, + { + RawArrayViewMut::from_shape_ptr(shape, ptr).deref_into_view_mut() + } + + /// Convert the view into an `ArrayViewMut<'b, A, D>` where `'b` is a lifetime + /// outlived by `'a'`. + pub fn reborrow<'b>(mut self) -> ArrayViewMut<'b, A, D> + where + 'a: 'b, + { + unsafe { ArrayViewMut::new_(self.as_mut_ptr(), self.dim, self.strides) } + } +} + +/// Private array view methods +impl<'a, A, D> ArrayView<'a, A, D> +where + D: Dimension, +{ + /// Create a new `ArrayView` + /// + /// Unsafe because: `ptr` must be valid for the given dimension and strides. + #[inline(always)] + pub(crate) unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self { + ArrayView { + data: ViewRepr::new(), + ptr: ptr as *mut A, + dim, + strides, + } + } +} + +impl<'a, A, D> ArrayViewMut<'a, A, D> +where + D: Dimension, +{ + /// Create a new `ArrayView` + /// + /// Unsafe because: `ptr` must be valid for the given dimension and strides. + #[inline(always)] + pub(crate) unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self { + if cfg!(debug_assertions) { + assert!(!ptr.is_null(), "The pointer must be non-null."); + assert!(is_aligned(ptr), "The pointer must be aligned."); + dimension::max_abs_offset_check_overflow::(&dim, &strides).unwrap(); + } + ArrayViewMut { + data: ViewRepr::new(), + ptr, + dim, + strides, + } + } +} diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs new file mode 100644 index 000000000..312e7080a --- /dev/null +++ b/src/impl_views/conversions.rs @@ -0,0 +1,146 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::slice; + +use crate::imp_prelude::*; + +use crate::{Baseiter, ElementsBase, ElementsBaseMut, Iter, IterMut}; + +use crate::iter::{self, AxisIter, AxisIterMut}; + +/// Methods for read-only array views. +impl<'a, A, D> ArrayView<'a, A, D> +where + D: Dimension, +{ + /// Convert the view into an `ArrayView<'b, A, D>` where `'b` is a lifetime + /// outlived by `'a'`. + pub fn reborrow<'b>(self) -> ArrayView<'b, A, D> + where + 'a: 'b, + { + unsafe { ArrayView::new_(self.as_ptr(), self.dim, self.strides) } + } + + /// Return the array’s data as a slice, if it is contiguous and in standard order. + /// Return `None` otherwise. + #[deprecated(note = "`into_slice` has been renamed to `to_slice`", since = "0.13.0")] + #[allow(clippy::wrong_self_convention)] + pub fn into_slice(&self) -> Option<&'a [A]> { + if self.is_standard_layout() { + unsafe { Some(slice::from_raw_parts(self.ptr, self.len())) } + } else { + None + } + } + + /// Return the array’s data as a slice, if it is contiguous and in standard order. + /// Return `None` otherwise. + pub fn to_slice(&self) -> Option<&'a [A]> { + if self.is_standard_layout() { + unsafe { Some(slice::from_raw_parts(self.ptr, self.len())) } + } else { + None + } + } + + /// Converts to a raw array view. + pub(crate) fn into_raw_view(self) -> RawArrayView { + unsafe { RawArrayView::new_(self.ptr, self.dim, self.strides) } + } +} + +/// Methods for read-write array views. +impl<'a, A, D> ArrayViewMut<'a, A, D> +where + D: Dimension, +{ + /// Return the array’s data as a slice, if it is contiguous and in standard order. + /// Return `None` otherwise. + pub fn into_slice(self) -> Option<&'a mut [A]> { + self.into_slice_().ok() + } +} + +/// Private array view methods +impl<'a, A, D> ArrayView<'a, A, D> +where + D: Dimension, +{ + #[inline] + pub(crate) fn into_base_iter(self) -> Baseiter { + unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + } + + #[inline] + pub(crate) fn into_elements_base(self) -> ElementsBase<'a, A, D> { + ElementsBase::new(self) + } + + pub(crate) fn into_iter_(self) -> Iter<'a, A, D> { + Iter::new(self) + } + + /// Return an outer iterator for this view. + #[doc(hidden)] // not official + #[deprecated(note = "This method will be replaced.")] + pub fn into_outer_iter(self) -> iter::AxisIter<'a, A, D::Smaller> + where + D: RemoveAxis, + { + AxisIter::new(self, Axis(0)) + } +} + +impl<'a, A, D> ArrayViewMut<'a, A, D> +where + D: Dimension, +{ + // Convert into a read-only view + pub(crate) fn into_view(self) -> ArrayView<'a, A, D> { + unsafe { ArrayView::new_(self.ptr, self.dim, self.strides) } + } + + /// Converts to a mutable raw array view. + pub(crate) fn into_raw_view_mut(self) -> RawArrayViewMut { + unsafe { RawArrayViewMut::new_(self.ptr, self.dim, self.strides) } + } + + #[inline] + pub(crate) fn into_base_iter(self) -> Baseiter { + unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } + } + + #[inline] + pub(crate) fn into_elements_base(self) -> ElementsBaseMut<'a, A, D> { + ElementsBaseMut::new(self) + } + + pub(crate) fn into_slice_(self) -> Result<&'a mut [A], Self> { + if self.is_standard_layout() { + unsafe { Ok(slice::from_raw_parts_mut(self.ptr, self.len())) } + } else { + Err(self) + } + } + + pub(crate) fn into_iter_(self) -> IterMut<'a, A, D> { + IterMut::new(self) + } + + /// Return an outer iterator for this view. + #[doc(hidden)] // not official + #[deprecated(note = "This method will be replaced.")] + pub fn into_outer_iter(self) -> iter::AxisIterMut<'a, A, D::Smaller> + where + D: RemoveAxis, + { + AxisIterMut::new(self, Axis(0)) + } +} diff --git a/src/impl_views/indexing.rs b/src/impl_views/indexing.rs new file mode 100644 index 000000000..b03c9a9c5 --- /dev/null +++ b/src/impl_views/indexing.rs @@ -0,0 +1,203 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::arraytraits::array_out_of_bounds; +use crate::imp_prelude::*; +use crate::NdIndex; + +/// Extra indexing methods for array views +/// +/// These methods are very similar to regular indexing or calling of the +/// `get`/`get_mut` methods that we can use on any array or array view. The +/// difference here is in the length of lifetime in the resulting reference. +/// +/// **Note** that the `ArrayView` (read-only) and `ArrayViewMut` (read-write) differ +/// in how they are allowed implement this trait -- `ArrayView`'s implementation +/// is usual. If you put in a `ArrayView<'a, T, D>` here, you get references +/// `&'a T` out. +/// +/// For `ArrayViewMut` to obey the borrowing rules we have to consume the +/// view if we call any of these methods. (The equivalent of reborrow is +/// `.view_mut()` for read-write array views, but if you can use that, +/// then the regular indexing / `get_mut` should suffice, too.) +/// +/// ``` +/// use ndarray::IndexLonger; +/// use ndarray::ArrayView; +/// +/// let data = [0.; 256]; +/// let long_life_ref = { +/// // make a 16 × 16 array view +/// let view = ArrayView::from(&data[..]).into_shape((16, 16)).unwrap(); +/// +/// // index the view and with `IndexLonger`. +/// // Note here that we get a reference with a life that is derived from +/// // `data`, the base data, instead of being derived from the view +/// IndexLonger::index(&view, [0, 1]) +/// }; +/// +/// // view goes out of scope +/// +/// assert_eq!(long_life_ref, &0.); +/// +/// ``` +pub trait IndexLonger { + /// The type of the reference to the element that is produced, including + /// its lifetime. + type Output; + /// Get a reference of a element through the view. + /// + /// This method is like `Index::index` but with a longer lifetime (matching + /// the array view); which we can only do for the array view and not in the + /// `Index` trait. + /// + /// See also [the `get` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.get + /// + /// **Panics** if index is out of bounds. + fn index(self, index: I) -> Self::Output; + + /// Get a reference of a element through the view. + /// + /// This method is like `ArrayBase::get` but with a longer lifetime (matching + /// the array view); which we can only do for the array view and not in the + /// `Index` trait. + /// + /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.get + /// [2]: struct.ArrayBase.html#method.get_mut + /// + /// **Panics** if index is out of bounds. + fn get(self, index: I) -> Option; + + /// Get a reference of a element through the view without boundary check + /// + /// This method is like `elem` with a longer lifetime (matching the array + /// view); which we can't do for general arrays. + /// + /// See also [the `uget` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.uget + /// + /// **Note:** only unchecked for non-debug builds of ndarray. + unsafe fn uget(self, index: I) -> Self::Output; +} + +impl<'a, 'b, I, A, D> IndexLonger for &'b ArrayView<'a, A, D> +where + I: NdIndex, + D: Dimension, +{ + type Output = &'a A; + + /// Get a reference of a element through the view. + /// + /// This method is like `Index::index` but with a longer lifetime (matching + /// the array view); which we can only do for the array view and not in the + /// `Index` trait. + /// + /// See also [the `get` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.get + /// + /// **Panics** if index is out of bounds. + fn index(self, index: I) -> &'a A { + debug_bounds_check!(self, index); + unsafe { &*self.get_ptr(index).unwrap_or_else(|| array_out_of_bounds()) } + } + + fn get(self, index: I) -> Option<&'a A> { + unsafe { self.get_ptr(index).map(|ptr| &*ptr) } + } + + /// Get a reference of a element through the view without boundary check + /// + /// This method is like `elem` with a longer lifetime (matching the array + /// view); which we can't do for general arrays. + /// + /// See also [the `uget` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.uget + /// + /// **Note:** only unchecked for non-debug builds of ndarray. + unsafe fn uget(self, index: I) -> &'a A { + debug_bounds_check!(self, index); + &*self.as_ptr().offset(index.index_unchecked(&self.strides)) + } +} + +impl<'a, I, A, D> IndexLonger for ArrayViewMut<'a, A, D> +where + I: NdIndex, + D: Dimension, +{ + type Output = &'a mut A; + + /// Convert a mutable array view to a mutable reference of a element. + /// + /// This method is like `IndexMut::index_mut` but with a longer lifetime + /// (matching the array view); which we can only do for the array view and + /// not in the `Index` trait. + /// + /// See also [the `get_mut` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.get_mut + /// + /// **Panics** if index is out of bounds. + fn index(mut self, index: I) -> &'a mut A { + debug_bounds_check!(self, index); + unsafe { + match self.get_ptr_mut(index) { + Some(ptr) => &mut *ptr, + None => array_out_of_bounds(), + } + } + } + + /// Convert a mutable array view to a mutable reference of a element, with + /// checked access. + /// + /// See also [the `get_mut` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.get_mut + /// + fn get(mut self, index: I) -> Option<&'a mut A> { + debug_bounds_check!(self, index); + unsafe { + match self.get_ptr_mut(index) { + Some(ptr) => Some(&mut *ptr), + None => None, + } + } + } + + /// Convert a mutable array view to a mutable reference of a element without + /// boundary check. + /// + /// See also [the `uget_mut` method][1] which works for all arrays and array + /// views. + /// + /// [1]: struct.ArrayBase.html#method.uget_mut + /// + /// **Note:** only unchecked for non-debug builds of ndarray. + unsafe fn uget(mut self, index: I) -> &'a mut A { + debug_bounds_check!(self, index); + &mut *self + .as_mut_ptr() + .offset(index.index_unchecked(&self.strides)) + } +} diff --git a/src/impl_views/mod.rs b/src/impl_views/mod.rs index 220c6b28d..487cc3cb2 100644 --- a/src/impl_views/mod.rs +++ b/src/impl_views/mod.rs @@ -1,648 +1,9 @@ -// Copyright 2014-2016 bluss and ndarray developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::slice; - -use crate::arraytraits::array_out_of_bounds; -use crate::dimension; -use crate::error::ShapeError; -use crate::imp_prelude::*; -use crate::{is_aligned, NdIndex, StrideShape}; - -use crate::{Baseiter, ElementsBase, ElementsBaseMut, Iter, IterMut}; - -use crate::iter::{self, AxisIter, AxisIterMut}; - -/// Methods for read-only array views. -impl<'a, A, D> ArrayView<'a, A, D> - where - D: Dimension, -{ - /// Create a read-only array view borrowing its data from a slice. - /// - /// Checks whether `shape` are compatible with the slice's - /// length, returning an `Err` if not compatible. - /// - /// ``` - /// use ndarray::ArrayView; - /// use ndarray::arr3; - /// use ndarray::ShapeBuilder; - /// - /// let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; - /// let a = ArrayView::from_shape((2, 3, 2).strides((1, 4, 2)), - /// &s).unwrap(); - /// - /// assert!( - /// a == arr3(&[[[0, 2], - /// [4, 6], - /// [8, 10]], - /// [[1, 3], - /// [5, 7], - /// [9, 11]]]) - /// ); - /// assert!(a.strides() == &[1, 4, 2]); - /// ``` - pub fn from_shape(shape: Sh, xs: &'a [A]) -> Result - where - Sh: Into>, - { - // eliminate the type parameter Sh as soon as possible - Self::from_shape_impl(shape.into(), xs) - } - - fn from_shape_impl(shape: StrideShape, xs: &'a [A]) -> Result { - let dim = shape.dim; - let strides = shape.strides; - if shape.custom { - dimension::can_index_slice(xs, &dim, &strides)?; - } else { - dimension::can_index_slice_not_custom::(xs, &dim)?; - } - unsafe { Ok(Self::new_(xs.as_ptr(), dim, strides)) } - } - - /// Create an `ArrayView` from shape information and a raw pointer to - /// the elements. - /// - /// Unsafe because caller is responsible for ensuring all of the following: - /// - /// * The elements seen by moving `ptr` according to the shape and strides - /// must live at least as long as `'a` and must not be not mutably - /// aliased for the duration of `'a`. - /// - /// * `ptr` must be non-null and aligned, and it must be safe to - /// [`.offset()`] `ptr` by zero. - /// - /// * It must be safe to [`.offset()`] the pointer repeatedly along all - /// axes and calculate the `count`s for the `.offset()` calls without - /// overflow, even if the array is empty or the elements are zero-sized. - /// - /// In other words, - /// - /// * All possible pointers generated by moving along all axes must be in - /// bounds or one byte past the end of a single allocation with element - /// type `A`. The only exceptions are if the array is empty or the element - /// type is zero-sized. In these cases, `ptr` may be dangling, but it must - /// still be safe to [`.offset()`] the pointer along the axes. - /// - /// * The offset in units of bytes between the least address and greatest - /// address by moving along all axes must not exceed `isize::MAX`. This - /// constraint prevents the computed offset, in bytes, from overflowing - /// `isize` regardless of the starting point due to past offsets. - /// - /// * The offset in units of `A` between the least address and greatest - /// address by moving along all axes must not exceed `isize::MAX`. This - /// constraint prevents overflow when calculating the `count` parameter to - /// [`.offset()`] regardless of the starting point due to past offsets. - /// - /// * The product of non-zero axis lengths must not exceed `isize::MAX`. - /// - /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset - pub unsafe fn from_shape_ptr(shape: Sh, ptr: *const A) -> Self - where - Sh: Into>, - { - RawArrayView::from_shape_ptr(shape, ptr).deref_into_view() - } - - /// Convert the view into an `ArrayView<'b, A, D>` where `'b` is a lifetime - /// outlived by `'a'`. - pub fn reborrow<'b>(self) -> ArrayView<'b, A, D> - where - 'a: 'b, - { - unsafe { ArrayView::new_(self.as_ptr(), self.dim, self.strides) } - } - - /// Split the array view along `axis` and return one view strictly before the - /// split and one view after the split. - /// - /// **Panics** if `axis` or `index` is out of bounds. - /// - /// **Examples:** - /// ```rust - /// # use ndarray::prelude::*; - /// let a = aview2(&[[0, 1, 2, 3], - /// [4, 5, 6, 7], - /// [8, 9, 0, 1]]); - /// - /// ``` - /// The array view `a` has two axes and shape 3 × 4: - /// ```text - /// ──▶ Axis(1) - /// ┌─────┬─────┬─────┬─────┐ 0 - /// │ │ a₀₀ │ a₀₁ │ a₀₂ │ a₀₃ │ - /// ▼ ├─────┼─────┼─────┼─────┤ 1 - /// Axis(0)│ a₁₀ │ a₁₁ │ a₁₂ │ a₁₃ │ - /// ├─────┼─────┼─────┼─────┤ 2 - /// │ a₂₀ │ a₂₁ │ a₂₂ │ a₂₃ │ - /// └─────┴─────┴─────┴─────┘ 3 ↑ - /// 0 1 2 3 4 ← possible split_at indices. - /// ``` - /// - /// Row indices increase along `Axis(0)`, and column indices increase along - /// `Axis(1)`. Note that we split “before” an element index, and that - /// both 0 and the endpoint are valid split indices. - /// - /// **Example 1**: Split `a` along the first axis, in this case the rows, at - /// index 1.
- /// This produces views v1 and v2 of shapes 1 × 4 and 2 × 4: - /// - /// ```rust - /// # use ndarray::prelude::*; - /// # let a = aview2(&[[0; 4]; 3]); - /// let (v1, v2) = a.split_at(Axis(0), 1); - /// ``` - /// ```text - /// ┌─────┬─────┬─────┬─────┐ 0 ↓ indices - /// │ a₀₀ │ a₀₁ │ a₀₂ │ a₀₃ │ along Axis(0) - /// ├─────┼─────┼─────┼─────┤ v1 1 - /// │ a₁₀ │ a₁₁ │ a₁₂ │ a₁₃ │ - /// └─────┴─────┴─────┴─────┘ - /// ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 2 - /// ┌─────┬─────┬─────┬─────┐ - /// │ a₂₀ │ a₂₁ │ a₂₂ │ a₂₃ │ v2 - /// └─────┴─────┴─────┴─────┘ 3 - /// ``` - /// - /// **Example 2**: Split `a` along the second axis, in this case the - /// columns, at index 2.
- /// This produces views u1 and u2 of shapes 3 × 2 and 3 × 2: - /// - /// ```rust - /// # use ndarray::prelude::*; - /// # let a = aview2(&[[0; 4]; 3]); - /// let (u1, u2) = a.split_at(Axis(1), 2); - /// - /// ``` - /// ```text - /// u1 u2 - /// ┌─────┬─────┐┊┌─────┬─────┐ - /// │ a₀₀ │ a₀₁ │┊│ a₀₂ │ a₀₃ │ - /// ├─────┼─────┤┊├─────┼─────┤ - /// │ a₁₀ │ a₁₁ │┊│ a₁₂ │ a₁₃ │ - /// ├─────┼─────┤┊├─────┼─────┤ - /// │ a₂₀ │ a₂₁ │┊│ a₂₂ │ a₂₃ │ - /// └─────┴─────┘┊└─────┴─────┘ - /// 0 1 2 3 4 indices → - /// along Axis(1) - /// ``` - pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { - unsafe { - let (left, right) = self.into_raw_view().split_at(axis, index); - (left.deref_into_view(), right.deref_into_view()) - } - } - - /// Return the array’s data as a slice, if it is contiguous and in standard order. - /// Return `None` otherwise. - #[deprecated(note = "`into_slice` has been renamed to `to_slice`", since = "0.13.0")] - #[allow(clippy::wrong_self_convention)] - pub fn into_slice(&self) -> Option<&'a [A]> { - if self.is_standard_layout() { - unsafe { Some(slice::from_raw_parts(self.ptr, self.len())) } - } else { - None - } - } - - /// Return the array’s data as a slice, if it is contiguous and in standard order. - /// Return `None` otherwise. - pub fn to_slice(&self) -> Option<&'a [A]> { - if self.is_standard_layout() { - unsafe { Some(slice::from_raw_parts(self.ptr, self.len())) } - } else { - None - } - } - - /// Converts to a raw array view. - pub(crate) fn into_raw_view(self) -> RawArrayView { - unsafe { RawArrayView::new_(self.ptr, self.dim, self.strides) } - } -} - -/// Extra indexing methods for array views -/// -/// These methods are very similar to regular indexing or calling of the -/// `get`/`get_mut` methods that we can use on any array or array view. The -/// difference here is in the length of lifetime in the resulting reference. -/// -/// **Note** that the `ArrayView` (read-only) and `ArrayViewMut` (read-write) differ -/// in how they are allowed implement this trait -- `ArrayView`'s implementation -/// is usual. If you put in a `ArrayView<'a, T, D>` here, you get references -/// `&'a T` out. -/// -/// For `ArrayViewMut` to obey the borrowing rules we have to consume the -/// view if we call any of these methods. (The equivalent of reborrow is -/// `.view_mut()` for read-write array views, but if you can use that, -/// then the regular indexing / `get_mut` should suffice, too.) -/// -/// ``` -/// use ndarray::IndexLonger; -/// use ndarray::ArrayView; -/// -/// let data = [0.; 256]; -/// let long_life_ref = { -/// // make a 16 × 16 array view -/// let view = ArrayView::from(&data[..]).into_shape((16, 16)).unwrap(); -/// -/// // index the view and with `IndexLonger`. -/// // Note here that we get a reference with a life that is derived from -/// // `data`, the base data, instead of being derived from the view -/// IndexLonger::index(&view, [0, 1]) -/// }; -/// -/// // view goes out of scope -/// -/// assert_eq!(long_life_ref, &0.); -/// -/// ``` -pub trait IndexLonger { - /// The type of the reference to the element that is produced, including - /// its lifetime. - type Output; - /// Get a reference of a element through the view. - /// - /// This method is like `Index::index` but with a longer lifetime (matching - /// the array view); which we can only do for the array view and not in the - /// `Index` trait. - /// - /// See also [the `get` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.get - /// - /// **Panics** if index is out of bounds. - fn index(self, index: I) -> Self::Output; - - /// Get a reference of a element through the view. - /// - /// This method is like `ArrayBase::get` but with a longer lifetime (matching - /// the array view); which we can only do for the array view and not in the - /// `Index` trait. - /// - /// See also [the `get` method][1] (and [`get_mut`][2]) which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.get - /// [2]: struct.ArrayBase.html#method.get_mut - /// - /// **Panics** if index is out of bounds. - fn get(self, index: I) -> Option; - - /// Get a reference of a element through the view without boundary check - /// - /// This method is like `elem` with a longer lifetime (matching the array - /// view); which we can't do for general arrays. - /// - /// See also [the `uget` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.uget - /// - /// **Note:** only unchecked for non-debug builds of ndarray. - unsafe fn uget(self, index: I) -> Self::Output; -} - -impl<'a, 'b, I, A, D> IndexLonger for &'b ArrayView<'a, A, D> - where - I: NdIndex, - D: Dimension, -{ - type Output = &'a A; - - /// Get a reference of a element through the view. - /// - /// This method is like `Index::index` but with a longer lifetime (matching - /// the array view); which we can only do for the array view and not in the - /// `Index` trait. - /// - /// See also [the `get` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.get - /// - /// **Panics** if index is out of bounds. - fn index(self, index: I) -> &'a A { - debug_bounds_check!(self, index); - unsafe { &*self.get_ptr(index).unwrap_or_else(|| array_out_of_bounds()) } - } - - fn get(self, index: I) -> Option<&'a A> { - unsafe { self.get_ptr(index).map(|ptr| &*ptr) } - } - - /// Get a reference of a element through the view without boundary check - /// - /// This method is like `elem` with a longer lifetime (matching the array - /// view); which we can't do for general arrays. - /// - /// See also [the `uget` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.uget - /// - /// **Note:** only unchecked for non-debug builds of ndarray. - unsafe fn uget(self, index: I) -> &'a A { - debug_bounds_check!(self, index); - &*self.as_ptr().offset(index.index_unchecked(&self.strides)) - } -} - -/// Methods for read-write array views. -impl<'a, A, D> ArrayViewMut<'a, A, D> - where - D: Dimension, -{ - /// Create a read-write array view borrowing its data from a slice. - /// - /// Checks whether `dim` and `strides` are compatible with the slice's - /// length, returning an `Err` if not compatible. - /// - /// ``` - /// use ndarray::ArrayViewMut; - /// use ndarray::arr3; - /// use ndarray::ShapeBuilder; - /// - /// let mut s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; - /// let mut a = ArrayViewMut::from_shape((2, 3, 2).strides((1, 4, 2)), - /// &mut s).unwrap(); - /// - /// a[[0, 0, 0]] = 1; - /// assert!( - /// a == arr3(&[[[1, 2], - /// [4, 6], - /// [8, 10]], - /// [[1, 3], - /// [5, 7], - /// [9, 11]]]) - /// ); - /// assert!(a.strides() == &[1, 4, 2]); - /// ``` - pub fn from_shape(shape: Sh, xs: &'a mut [A]) -> Result - where - Sh: Into>, - { - // eliminate the type parameter Sh as soon as possible - Self::from_shape_impl(shape.into(), xs) - } - - fn from_shape_impl(shape: StrideShape, xs: &'a mut [A]) -> Result { - let dim = shape.dim; - let strides = shape.strides; - if shape.custom { - dimension::can_index_slice(xs, &dim, &strides)?; - } else { - dimension::can_index_slice_not_custom::(xs, &dim)?; - } - unsafe { Ok(Self::new_(xs.as_mut_ptr(), dim, strides)) } - } - - /// Create an `ArrayViewMut` from shape information and a - /// raw pointer to the elements. - /// - /// Unsafe because caller is responsible for ensuring all of the following: - /// - /// * The elements seen by moving `ptr` according to the shape and strides - /// must live at least as long as `'a` and must not be aliased for the - /// duration of `'a`. - /// - /// * `ptr` must be non-null and aligned, and it must be safe to - /// [`.offset()`] `ptr` by zero. - /// - /// * It must be safe to [`.offset()`] the pointer repeatedly along all - /// axes and calculate the `count`s for the `.offset()` calls without - /// overflow, even if the array is empty or the elements are zero-sized. - /// - /// In other words, - /// - /// * All possible pointers generated by moving along all axes must be in - /// bounds or one byte past the end of a single allocation with element - /// type `A`. The only exceptions are if the array is empty or the element - /// type is zero-sized. In these cases, `ptr` may be dangling, but it must - /// still be safe to [`.offset()`] the pointer along the axes. - /// - /// * The offset in units of bytes between the least address and greatest - /// address by moving along all axes must not exceed `isize::MAX`. This - /// constraint prevents the computed offset, in bytes, from overflowing - /// `isize` regardless of the starting point due to past offsets. - /// - /// * The offset in units of `A` between the least address and greatest - /// address by moving along all axes must not exceed `isize::MAX`. This - /// constraint prevents overflow when calculating the `count` parameter to - /// [`.offset()`] regardless of the starting point due to past offsets. - /// - /// * The product of non-zero axis lengths must not exceed `isize::MAX`. - /// - /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset - pub unsafe fn from_shape_ptr(shape: Sh, ptr: *mut A) -> Self - where - Sh: Into>, - { - RawArrayViewMut::from_shape_ptr(shape, ptr).deref_into_view_mut() - } - - /// Convert the view into an `ArrayViewMut<'b, A, D>` where `'b` is a lifetime - /// outlived by `'a'`. - pub fn reborrow<'b>(mut self) -> ArrayViewMut<'b, A, D> - where - 'a: 'b, - { - unsafe { ArrayViewMut::new_(self.as_mut_ptr(), self.dim, self.strides) } - } - - /// Split the array view along `axis` and return one mutable view strictly - /// before the split and one mutable view after the split. - /// - /// **Panics** if `axis` or `index` is out of bounds. - pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { - unsafe { - let (left, right) = self.into_raw_view_mut().split_at(axis, index); - (left.deref_into_view_mut(), right.deref_into_view_mut()) - } - } - - /// Return the array’s data as a slice, if it is contiguous and in standard order. - /// Return `None` otherwise. - pub fn into_slice(self) -> Option<&'a mut [A]> { - self.into_slice_().ok() - } -} - -impl<'a, I, A, D> IndexLonger for ArrayViewMut<'a, A, D> - where - I: NdIndex, - D: Dimension, -{ - type Output = &'a mut A; - - /// Convert a mutable array view to a mutable reference of a element. - /// - /// This method is like `IndexMut::index_mut` but with a longer lifetime - /// (matching the array view); which we can only do for the array view and - /// not in the `Index` trait. - /// - /// See also [the `get_mut` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.get_mut - /// - /// **Panics** if index is out of bounds. - fn index(mut self, index: I) -> &'a mut A { - debug_bounds_check!(self, index); - unsafe { - match self.get_ptr_mut(index) { - Some(ptr) => &mut *ptr, - None => array_out_of_bounds(), - } - } - } - - /// Convert a mutable array view to a mutable reference of a element, with - /// checked access. - /// - /// See also [the `get_mut` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.get_mut - /// - fn get(mut self, index: I) -> Option<&'a mut A> { - debug_bounds_check!(self, index); - unsafe { - match self.get_ptr_mut(index) { - Some(ptr) => Some(&mut *ptr), - None => None, - } - } - } - - /// Convert a mutable array view to a mutable reference of a element without - /// boundary check. - /// - /// See also [the `uget_mut` method][1] which works for all arrays and array - /// views. - /// - /// [1]: struct.ArrayBase.html#method.uget_mut - /// - /// **Note:** only unchecked for non-debug builds of ndarray. - unsafe fn uget(mut self, index: I) -> &'a mut A { - debug_bounds_check!(self, index); - &mut *self - .as_mut_ptr() - .offset(index.index_unchecked(&self.strides)) - } -} - -/// Private array view methods -impl<'a, A, D> ArrayView<'a, A, D> - where - D: Dimension, -{ - /// Create a new `ArrayView` - /// - /// Unsafe because: `ptr` must be valid for the given dimension and strides. - #[inline(always)] - pub(crate) unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self { - ArrayView { - data: ViewRepr::new(), - ptr: ptr as *mut A, - dim, - strides, - } - } - - #[inline] - pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } - } - - #[inline] - pub(crate) fn into_elements_base(self) -> ElementsBase<'a, A, D> { - ElementsBase::new(self) - } - - pub(crate) fn into_iter_(self) -> Iter<'a, A, D> { - Iter::new(self) - } - - /// Return an outer iterator for this view. - #[doc(hidden)] // not official - #[deprecated(note = "This method will be replaced.")] - pub fn into_outer_iter(self) -> iter::AxisIter<'a, A, D::Smaller> - where - D: RemoveAxis, - { - AxisIter::new(self, Axis(0)) - } -} - -impl<'a, A, D> ArrayViewMut<'a, A, D> - where - D: Dimension, -{ - /// Create a new `ArrayView` - /// - /// Unsafe because: `ptr` must be valid for the given dimension and strides. - #[inline(always)] - pub(crate) unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self { - if cfg!(debug_assertions) { - assert!(!ptr.is_null(), "The pointer must be non-null."); - assert!(is_aligned(ptr), "The pointer must be aligned."); - dimension::max_abs_offset_check_overflow::(&dim, &strides).unwrap(); - } - ArrayViewMut { - data: ViewRepr::new(), - ptr, - dim, - strides, - } - } - - // Convert into a read-only view - pub(crate) fn into_view(self) -> ArrayView<'a, A, D> { - unsafe { ArrayView::new_(self.ptr, self.dim, self.strides) } - } - - /// Converts to a mutable raw array view. - pub(crate) fn into_raw_view_mut(self) -> RawArrayViewMut { - unsafe { RawArrayViewMut::new_(self.ptr, self.dim, self.strides) } - } - - #[inline] - pub(crate) fn into_base_iter(self) -> Baseiter { - unsafe { Baseiter::new(self.ptr, self.dim, self.strides) } - } - - #[inline] - pub(crate) fn into_elements_base(self) -> ElementsBaseMut<'a, A, D> { - ElementsBaseMut::new(self) - } - - pub(crate) fn into_slice_(self) -> Result<&'a mut [A], Self> { - if self.is_standard_layout() { - unsafe { Ok(slice::from_raw_parts_mut(self.ptr, self.len())) } - } else { - Err(self) - } - } - - pub(crate) fn into_iter_(self) -> IterMut<'a, A, D> { - IterMut::new(self) - } - - /// Return an outer iterator for this view. - #[doc(hidden)] // not official - #[deprecated(note = "This method will be replaced.")] - pub fn into_outer_iter(self) -> iter::AxisIterMut<'a, A, D::Smaller> - where - D: RemoveAxis, - { - AxisIterMut::new(self, Axis(0)) - } -} +mod constructors; +mod conversions; +mod indexing; +mod splitting; + +pub use constructors::*; +pub use conversions::*; +pub use indexing::*; +pub use splitting::*; diff --git a/src/impl_views/splitting.rs b/src/impl_views/splitting.rs new file mode 100644 index 000000000..dd6b87a0c --- /dev/null +++ b/src/impl_views/splitting.rs @@ -0,0 +1,112 @@ +// Copyright 2014-2016 bluss and ndarray developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::imp_prelude::*; + +/// Methods for read-only array views. +impl<'a, A, D> ArrayView<'a, A, D> +where + D: Dimension, +{ + /// Split the array view along `axis` and return one view strictly before the + /// split and one view after the split. + /// + /// **Panics** if `axis` or `index` is out of bounds. + /// + /// **Examples:** + /// ```rust + /// # use ndarray::prelude::*; + /// let a = aview2(&[[0, 1, 2, 3], + /// [4, 5, 6, 7], + /// [8, 9, 0, 1]]); + /// + /// ``` + /// The array view `a` has two axes and shape 3 × 4: + /// ```text + /// ──▶ Axis(1) + /// ┌─────┬─────┬─────┬─────┐ 0 + /// │ │ a₀₀ │ a₀₁ │ a₀₂ │ a₀₃ │ + /// ▼ ├─────┼─────┼─────┼─────┤ 1 + /// Axis(0)│ a₁₀ │ a₁₁ │ a₁₂ │ a₁₃ │ + /// ├─────┼─────┼─────┼─────┤ 2 + /// │ a₂₀ │ a₂₁ │ a₂₂ │ a₂₃ │ + /// └─────┴─────┴─────┴─────┘ 3 ↑ + /// 0 1 2 3 4 ← possible split_at indices. + /// ``` + /// + /// Row indices increase along `Axis(0)`, and column indices increase along + /// `Axis(1)`. Note that we split “before” an element index, and that + /// both 0 and the endpoint are valid split indices. + /// + /// **Example 1**: Split `a` along the first axis, in this case the rows, at + /// index 1.
+ /// This produces views v1 and v2 of shapes 1 × 4 and 2 × 4: + /// + /// ```rust + /// # use ndarray::prelude::*; + /// # let a = aview2(&[[0; 4]; 3]); + /// let (v1, v2) = a.split_at(Axis(0), 1); + /// ``` + /// ```text + /// ┌─────┬─────┬─────┬─────┐ 0 ↓ indices + /// │ a₀₀ │ a₀₁ │ a₀₂ │ a₀₃ │ along Axis(0) + /// ├─────┼─────┼─────┼─────┤ v1 1 + /// │ a₁₀ │ a₁₁ │ a₁₂ │ a₁₃ │ + /// └─────┴─────┴─────┴─────┘ + /// ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 2 + /// ┌─────┬─────┬─────┬─────┐ + /// │ a₂₀ │ a₂₁ │ a₂₂ │ a₂₃ │ v2 + /// └─────┴─────┴─────┴─────┘ 3 + /// ``` + /// + /// **Example 2**: Split `a` along the second axis, in this case the + /// columns, at index 2.
+ /// This produces views u1 and u2 of shapes 3 × 2 and 3 × 2: + /// + /// ```rust + /// # use ndarray::prelude::*; + /// # let a = aview2(&[[0; 4]; 3]); + /// let (u1, u2) = a.split_at(Axis(1), 2); + /// + /// ``` + /// ```text + /// u1 u2 + /// ┌─────┬─────┐┊┌─────┬─────┐ + /// │ a₀₀ │ a₀₁ │┊│ a₀₂ │ a₀₃ │ + /// ├─────┼─────┤┊├─────┼─────┤ + /// │ a₁₀ │ a₁₁ │┊│ a₁₂ │ a₁₃ │ + /// ├─────┼─────┤┊├─────┼─────┤ + /// │ a₂₀ │ a₂₁ │┊│ a₂₂ │ a₂₃ │ + /// └─────┴─────┘┊└─────┴─────┘ + /// 0 1 2 3 4 indices → + /// along Axis(1) + /// ``` + pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { + unsafe { + let (left, right) = self.into_raw_view().split_at(axis, index); + (left.deref_into_view(), right.deref_into_view()) + } + } +} + +/// Methods for read-write array views. +impl<'a, A, D> ArrayViewMut<'a, A, D> +where + D: Dimension, +{ + /// Split the array view along `axis` and return one mutable view strictly + /// before the split and one mutable view after the split. + /// + /// **Panics** if `axis` or `index` is out of bounds. + pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) { + unsafe { + let (left, right) = self.into_raw_view_mut().split_at(axis, index); + (left.deref_into_view_mut(), right.deref_into_view_mut()) + } + } +} From 1333f19b2d739e14ef6903ca3f108c8dbee8eb5f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 17:38:58 +0100 Subject: [PATCH 4/7] Add into_scalar for ArrayView --- src/impl_views/conversions.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index 312e7080a..8dd2f92eb 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -13,6 +13,7 @@ use crate::imp_prelude::*; use crate::{Baseiter, ElementsBase, ElementsBaseMut, Iter, IterMut}; use crate::iter::{self, AxisIter, AxisIterMut}; +use crate::IndexLonger; /// Methods for read-only array views. impl<'a, A, D> ArrayView<'a, A, D> @@ -56,6 +57,36 @@ where } } + +/// Methods specific to `ArrayView0`. +/// +/// ***See also all methods for [`ArrayView`] and [`ArrayBase`]*** +/// +/// [`ArrayBase`]: struct.ArrayBase.html +/// [`ArrayView`]: struct.ArrayView.html +impl<'a, A> ArrayView<'a, A, Ix0> { + /// Consume the view and returns a reference to the single element in the array. + /// + /// The lifetime of the returned reference matches the lifetime of the data + /// the array view was pointing to. + /// + /// ``` + /// use ndarray::{arr0, Array0}; + /// + /// // `Foo` doesn't implement `Clone`. + /// #[derive(Debug, Eq, PartialEq)] + /// struct Foo; + /// + /// let array: Array0 = arr0(Foo); + /// let view = array.view(); + /// let scalar: &Foo = view.into_scalar(); + /// assert_eq!(scalar, &Foo); + /// ``` + pub fn into_scalar(self) -> &'a A { + self.index(Ix0()) + } +} + /// Methods for read-write array views. impl<'a, A, D> ArrayViewMut<'a, A, D> where From 2c4665e48e36c0c3aa2b59d5e9b38b2dfd0cfc13 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 17:42:25 +0100 Subject: [PATCH 5/7] Add test for array view into_scalar --- tests/array.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/array.rs b/tests/array.rs index 70802e2c5..d9e5b336b 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1031,6 +1031,21 @@ fn array0_into_scalar() { assert_eq!(a.into_scalar(), ()); } +#[test] +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().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); + + // It should work for zero-size elements too. + let a: Array0<()> = array![(), (), (), ()].index_axis_move(Axis(0), 2); + assert_eq!(a.view().into_scalar(), &()); +} + #[test] fn owned_array1() { let mut a = Array::from(vec![1, 2, 3, 4]); From 01b76cee1e394cec7f05c76a0f19ecd86bb24f0b Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 17:51:48 +0100 Subject: [PATCH 6/7] Refine docs, change doctest for the mutable version. --- src/impl_views/conversions.rs | 29 ++++++++++++++++++++++++++++- tests/array.rs | 15 +++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index 8dd2f92eb..d03de1221 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -65,7 +65,7 @@ where /// [`ArrayBase`]: struct.ArrayBase.html /// [`ArrayView`]: struct.ArrayView.html impl<'a, A> ArrayView<'a, A, Ix0> { - /// Consume the view and returns a reference to the single element in the array. + /// Consume the view and return a reference to the single element in the array. /// /// The lifetime of the returned reference matches the lifetime of the data /// the array view was pointing to. @@ -87,6 +87,33 @@ impl<'a, A> ArrayView<'a, A, Ix0> { } } +/// Methods specific to `ArrayViewMut0`. +/// +/// ***See also all methods for [`ArrayViewMut`] and [`ArrayBase`]*** +/// +/// [`ArrayBase`]: struct.ArrayBase.html +/// [`ArrayViewMut`]: struct.ArrayViewMut.html +impl<'a, A> ArrayViewMut<'a, A, Ix0> { + /// Consume the mutable view and return a mutable reference to the single element in the array. + /// + /// The lifetime of the returned reference matches the lifetime of the data + /// the array view was pointing to. + /// + /// ``` + /// use ndarray::{arr0, Array0}; + /// + /// let mut array: Array0 = arr0(5.); + /// let view = array.view_mut(); + /// let mut scalar = view.into_scalar(); + /// *scalar = 7.; + /// assert_eq!(scalar, &7.); + /// assert_eq!(array[()], 7.); + /// ``` + pub fn into_scalar(self) -> &'a mut A { + self.index(Ix0()) + } +} + /// Methods for read-write array views. impl<'a, A, D> ArrayViewMut<'a, A, D> where diff --git a/tests/array.rs b/tests/array.rs index d9e5b336b..f782ca342 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1046,6 +1046,21 @@ fn array_view0_into_scalar() { assert_eq!(a.view().into_scalar(), &()); } +#[test] +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().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); + + // It should work for zero-size elements too. + let mut a: Array0<()> = array![(), (), (), ()].index_axis_move(Axis(0), 2); + assert_eq!(a.view_mut().into_scalar(), &()); +} + #[test] fn owned_array1() { let mut a = Array::from(vec![1, 2, 3, 4]); From a95a8639ace68439514774dedd7cbf15b8d0bd52 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Sun, 8 Sep 2019 17:52:09 +0100 Subject: [PATCH 7/7] cargo fmt --- src/impl_views/conversions.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/impl_views/conversions.rs b/src/impl_views/conversions.rs index d03de1221..d01f1f976 100644 --- a/src/impl_views/conversions.rs +++ b/src/impl_views/conversions.rs @@ -57,7 +57,6 @@ where } } - /// Methods specific to `ArrayView0`. /// /// ***See also all methods for [`ArrayView`] and [`ArrayBase`]***