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