ndarray/impl_views/
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
9use std::ptr::NonNull;
10
11use crate::dimension;
12use crate::error::ShapeError;
13use crate::extension::nonnull::nonnull_debug_checked_from_ptr;
14use crate::imp_prelude::*;
15use crate::{is_aligned, StrideShape};
16use crate::dimension::offset_from_low_addr_ptr_to_logical_ptr;
17
18/// Methods for read-only array views.
19impl<'a, A, D> ArrayView<'a, A, D>
20where
21    D: Dimension,
22{
23    /// Create a read-only array view borrowing its data from a slice.
24    ///
25    /// Checks whether `shape` are compatible with the slice's
26    /// length, returning an `Err` if not compatible.
27    ///
28    /// ```
29    /// use ndarray::ArrayView;
30    /// use ndarray::arr3;
31    /// use ndarray::ShapeBuilder;
32    ///
33    /// // advanced example where we are even specifying exact strides to use (which is optional).
34    /// let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
35    /// let a = ArrayView::from_shape((2, 3, 2).strides((1, 4, 2)),
36    ///                               &s).unwrap();
37    ///
38    /// assert!(
39    ///     a == arr3(&[[[0, 2],
40    ///                  [4, 6],
41    ///                  [8, 10]],
42    ///                 [[1, 3],
43    ///                  [5, 7],
44    ///                  [9, 11]]])
45    /// );
46    /// assert!(a.strides() == &[1, 4, 2]);
47    /// ```
48    pub fn from_shape<Sh>(shape: Sh, xs: &'a [A]) -> Result<Self, ShapeError>
49    where
50        Sh: Into<StrideShape<D>>,
51    {
52        // eliminate the type parameter Sh as soon as possible
53        Self::from_shape_impl(shape.into(), xs)
54    }
55
56    fn from_shape_impl(shape: StrideShape<D>, xs: &'a [A]) -> Result<Self, ShapeError> {
57        let dim = shape.dim;
58        dimension::can_index_slice_with_strides(xs, &dim, &shape.strides)?;
59        let strides = shape.strides.strides_for_dim(&dim);
60        unsafe { Ok(Self::new_(xs.as_ptr().add(offset_from_low_addr_ptr_to_logical_ptr(&dim, &strides)), dim, strides)) }
61    }
62
63    /// Create an `ArrayView<A, D>` from shape information and a raw pointer to
64    /// the elements.
65    ///
66    /// # Safety
67    ///
68    /// The caller is responsible for ensuring all of the following:
69    ///
70    /// * The elements seen by moving `ptr` according to the shape and strides
71    ///   must live at least as long as `'a` and must not be not mutably
72    ///   aliased for the duration of `'a`.
73    ///
74    /// * `ptr` must be non-null and aligned, and it must be safe to
75    ///   [`.offset()`] `ptr` by zero.
76    ///
77    /// * It must be safe to [`.offset()`] the pointer repeatedly along all
78    ///   axes and calculate the `count`s for the `.offset()` calls without
79    ///   overflow, even if the array is empty or the elements are zero-sized.
80    ///
81    ///   In other words,
82    ///
83    ///   * All possible pointers generated by moving along all axes must be in
84    ///     bounds or one byte past the end of a single allocation with element
85    ///     type `A`. The only exceptions are if the array is empty or the element
86    ///     type is zero-sized. In these cases, `ptr` may be dangling, but it must
87    ///     still be safe to [`.offset()`] the pointer along the axes.
88    ///
89    ///   * The offset in units of bytes between the least address and greatest
90    ///     address by moving along all axes must not exceed `isize::MAX`. This
91    ///     constraint prevents the computed offset, in bytes, from overflowing
92    ///     `isize` regardless of the starting point due to past offsets.
93    ///
94    ///   * The offset in units of `A` between the least address and greatest
95    ///     address by moving along all axes must not exceed `isize::MAX`. This
96    ///     constraint prevents overflow when calculating the `count` parameter to
97    ///     [`.offset()`] regardless of the starting point due to past offsets.
98    ///
99    /// * The product of non-zero axis lengths must not exceed `isize::MAX`.
100    ///
101    /// * Strides must be non-negative.
102    ///
103    /// This function can use debug assertions to check some of these requirements,
104    /// but it's not a complete check.
105    ///
106    /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
107    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
108    where
109        Sh: Into<StrideShape<D>>,
110    {
111        RawArrayView::from_shape_ptr(shape, ptr).deref_into_view()
112    }
113}
114
115/// Methods for read-write array views.
116impl<'a, A, D> ArrayViewMut<'a, A, D>
117where
118    D: Dimension,
119{
120    /// Create a read-write array view borrowing its data from a slice.
121    ///
122    /// Checks whether `dim` and `strides` are compatible with the slice's
123    /// length, returning an `Err` if not compatible.
124    ///
125    /// ```
126    /// use ndarray::ArrayViewMut;
127    /// use ndarray::arr3;
128    /// use ndarray::ShapeBuilder;
129    ///
130    /// let mut s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
131    /// let mut a = ArrayViewMut::from_shape((2, 3, 2).strides((1, 4, 2)),
132    ///                                      &mut s).unwrap();
133    ///
134    /// a[[0, 0, 0]] = 1;
135    /// assert!(
136    ///     a == arr3(&[[[1, 2],
137    ///                  [4, 6],
138    ///                  [8, 10]],
139    ///                 [[1, 3],
140    ///                  [5, 7],
141    ///                  [9, 11]]])
142    /// );
143    /// assert!(a.strides() == &[1, 4, 2]);
144    /// ```
145    pub fn from_shape<Sh>(shape: Sh, xs: &'a mut [A]) -> Result<Self, ShapeError>
146    where
147        Sh: Into<StrideShape<D>>,
148    {
149        // eliminate the type parameter Sh as soon as possible
150        Self::from_shape_impl(shape.into(), xs)
151    }
152
153    fn from_shape_impl(shape: StrideShape<D>, xs: &'a mut [A]) -> Result<Self, ShapeError> {
154        let dim = shape.dim;
155        dimension::can_index_slice_with_strides(xs, &dim, &shape.strides)?;
156        let strides = shape.strides.strides_for_dim(&dim);
157        unsafe { Ok(Self::new_(xs.as_mut_ptr().add(offset_from_low_addr_ptr_to_logical_ptr(&dim, &strides)), dim, strides)) }
158    }
159
160    /// Create an `ArrayViewMut<A, D>` from shape information and a
161    /// raw pointer to the elements.
162    ///
163    /// # Safety
164    ///
165    /// The caller is responsible for ensuring all of the following:
166    ///
167    /// * The elements seen by moving `ptr` according to the shape and strides
168    ///   must live at least as long as `'a` and must not be aliased for the
169    ///   duration of `'a`.
170    ///
171    /// * `ptr` must be non-null and aligned, and it must be safe to
172    ///   [`.offset()`] `ptr` by zero.
173    ///
174    /// * It must be safe to [`.offset()`] the pointer repeatedly along all
175    ///   axes and calculate the `count`s for the `.offset()` calls without
176    ///   overflow, even if the array is empty or the elements are zero-sized.
177    ///
178    ///   In other words,
179    ///
180    ///   * All possible pointers generated by moving along all axes must be in
181    ///     bounds or one byte past the end of a single allocation with element
182    ///     type `A`. The only exceptions are if the array is empty or the element
183    ///     type is zero-sized. In these cases, `ptr` may be dangling, but it must
184    ///     still be safe to [`.offset()`] the pointer along the axes.
185    ///
186    ///   * The offset in units of bytes between the least address and greatest
187    ///     address by moving along all axes must not exceed `isize::MAX`. This
188    ///     constraint prevents the computed offset, in bytes, from overflowing
189    ///     `isize` regardless of the starting point due to past offsets.
190    ///
191    ///   * The offset in units of `A` between the least address and greatest
192    ///     address by moving along all axes must not exceed `isize::MAX`. This
193    ///     constraint prevents overflow when calculating the `count` parameter to
194    ///     [`.offset()`] regardless of the starting point due to past offsets.
195    ///
196    /// * The product of non-zero axis lengths must not exceed `isize::MAX`.
197    ///
198    /// * Strides must be non-negative.
199    ///
200    /// This function can use debug assertions to check some of these requirements,
201    /// but it's not a complete check.
202    ///
203    /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
204    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
205    where
206        Sh: Into<StrideShape<D>>,
207    {
208        RawArrayViewMut::from_shape_ptr(shape, ptr).deref_into_view_mut()
209    }
210
211    /// Convert the view into an `ArrayViewMut<'b, A, D>` where `'b` is a lifetime
212    /// outlived by `'a'`.
213    pub fn reborrow<'b>(self) -> ArrayViewMut<'b, A, D>
214    where
215        'a: 'b,
216    {
217        unsafe { ArrayViewMut::new(self.ptr, self.dim, self.strides) }
218    }
219}
220
221/// Private array view methods
222impl<'a, A, D> ArrayView<'a, A, D>
223where
224    D: Dimension,
225{
226    /// Create a new `ArrayView`
227    ///
228    /// Unsafe because: `ptr` must be valid for the given dimension and strides.
229    #[inline(always)]
230    pub(crate) unsafe fn new(ptr: NonNull<A>, dim: D, strides: D) -> Self {
231        if cfg!(debug_assertions) {
232            assert!(is_aligned(ptr.as_ptr()), "The pointer must be aligned.");
233            dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
234        }
235        ArrayView::from_data_ptr(ViewRepr::new(), ptr).with_strides_dim(strides, dim)
236    }
237
238    /// Unsafe because: `ptr` must be valid for the given dimension and strides.
239    #[inline]
240    pub(crate) unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self {
241        Self::new(nonnull_debug_checked_from_ptr(ptr as *mut A), dim, strides)
242    }
243}
244
245impl<'a, A, D> ArrayViewMut<'a, A, D>
246where
247    D: Dimension,
248{
249    /// Create a new `ArrayView`
250    ///
251    /// Unsafe because: `ptr` must be valid for the given dimension and strides.
252    #[inline(always)]
253    pub(crate) unsafe fn new(ptr: NonNull<A>, dim: D, strides: D) -> Self {
254        if cfg!(debug_assertions) {
255            assert!(is_aligned(ptr.as_ptr()), "The pointer must be aligned.");
256            dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
257        }
258        ArrayViewMut::from_data_ptr(ViewRepr::new(), ptr).with_strides_dim(strides, dim)
259    }
260
261    /// Create a new `ArrayView`
262    ///
263    /// Unsafe because: `ptr` must be valid for the given dimension and strides.
264    #[inline(always)]
265    pub(crate) unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self {
266        Self::new(nonnull_debug_checked_from_ptr(ptr), dim, strides)
267    }
268}