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}