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}