ndarray/impl_raw_views.rs
1use std::mem;
2use std::ptr::NonNull;
3
4use crate::dimension::{self, stride_offset};
5use crate::extension::nonnull::nonnull_debug_checked_from_ptr;
6use crate::imp_prelude::*;
7use crate::is_aligned;
8use crate::shape_builder::{Strides, StrideShape};
9
10impl<A, D> RawArrayView<A, D>
11where
12 D: Dimension,
13{
14 /// Create a new `RawArrayView`.
15 ///
16 /// Unsafe because caller is responsible for ensuring that the array will
17 /// meet all of the invariants of the `ArrayBase` type.
18 #[inline]
19 pub(crate) unsafe fn new(ptr: NonNull<A>, dim: D, strides: D) -> Self {
20 RawArrayView::from_data_ptr(RawViewRepr::new(), ptr)
21 .with_strides_dim(strides, dim)
22 }
23
24 unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self {
25 Self::new(nonnull_debug_checked_from_ptr(ptr as *mut A), dim, strides)
26 }
27
28 /// Create an `RawArrayView<A, D>` from shape information and a raw pointer
29 /// to the elements.
30 ///
31 /// # Safety
32 ///
33 /// The caller is responsible for ensuring all of the following:
34 ///
35 /// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
36 /// zero.
37 ///
38 /// * It must be safe to [`.offset()`] the pointer repeatedly along all
39 /// axes and calculate the `count`s for the `.offset()` calls without
40 /// overflow, even if the array is empty or the elements are zero-sized.
41 ///
42 /// In other words,
43 ///
44 /// * All possible pointers generated by moving along all axes must be in
45 /// bounds or one byte past the end of a single allocation with element
46 /// type `A`. The only exceptions are if the array is empty or the element
47 /// type is zero-sized. In these cases, `ptr` may be dangling, but it must
48 /// still be safe to [`.offset()`] the pointer along the axes.
49 ///
50 /// * The offset in units of bytes between the least address and greatest
51 /// address by moving along all axes must not exceed `isize::MAX`. This
52 /// constraint prevents the computed offset, in bytes, from overflowing
53 /// `isize` regardless of the starting point due to past offsets.
54 ///
55 /// * The offset in units of `A` between the least address and greatest
56 /// address by moving along all axes must not exceed `isize::MAX`. This
57 /// constraint prevents overflow when calculating the `count` parameter to
58 /// [`.offset()`] regardless of the starting point due to past offsets.
59 ///
60 /// * The product of non-zero axis lengths must not exceed `isize::MAX`.
61 ///
62 /// * Strides must be non-negative.
63 ///
64 /// This function can use debug assertions to check some of these requirements,
65 /// but it's not a complete check.
66 ///
67 /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
68 pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
69 where
70 Sh: Into<StrideShape<D>>,
71 {
72 let shape = shape.into();
73 let dim = shape.dim;
74 if cfg!(debug_assertions) {
75 assert!(!ptr.is_null(), "The pointer must be non-null.");
76 if let Strides::Custom(strides) = &shape.strides {
77 dimension::strides_non_negative(strides).unwrap();
78 dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
79 } else {
80 dimension::size_of_shape_checked(&dim).unwrap();
81 }
82 }
83 let strides = shape.strides.strides_for_dim(&dim);
84 RawArrayView::new_(ptr, dim, strides)
85 }
86
87 /// Converts to a read-only view of the array.
88 ///
89 /// # Safety
90 ///
91 /// From a safety standpoint, this is equivalent to dereferencing a raw
92 /// pointer for every element in the array. You must ensure that all of the
93 /// data is valid, ensure that the pointer is aligned, and choose the
94 /// correct lifetime.
95 #[inline]
96 pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
97 debug_assert!(
98 is_aligned(self.ptr.as_ptr()),
99 "The pointer must be aligned."
100 );
101 ArrayView::new(self.ptr, self.dim, self.strides)
102 }
103
104 /// Split the array view along `axis` and return one array pointer strictly
105 /// before the split and one array pointer after the split.
106 ///
107 /// **Panics** if `axis` or `index` is out of bounds.
108 pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) {
109 assert!(index <= self.len_of(axis));
110 let left_ptr = self.ptr.as_ptr();
111 let right_ptr = if index == self.len_of(axis) {
112 self.ptr.as_ptr()
113 } else {
114 let offset = stride_offset(index, self.strides.axis(axis));
115 // The `.offset()` is safe due to the guarantees of `RawData`.
116 unsafe { self.ptr.as_ptr().offset(offset) }
117 };
118
119 let mut dim_left = self.dim.clone();
120 dim_left.set_axis(axis, index);
121 let left = unsafe { Self::new_(left_ptr, dim_left, self.strides.clone()) };
122
123 let mut dim_right = self.dim;
124 let right_len = dim_right.axis(axis) - index;
125 dim_right.set_axis(axis, right_len);
126 let right = unsafe { Self::new_(right_ptr, dim_right, self.strides) };
127
128 (left, right)
129 }
130
131 /// Cast the raw pointer of the raw array view to a different type
132 ///
133 /// **Panics** if element size is not compatible.
134 ///
135 /// Lack of panic does not imply it is a valid cast. The cast works the same
136 /// way as regular raw pointer casts.
137 ///
138 /// While this method is safe, for the same reason as regular raw pointer
139 /// casts are safe, access through the produced raw view is only possible
140 /// in an unsafe block or function.
141 pub fn cast<B>(self) -> RawArrayView<B, D> {
142 assert_eq!(
143 mem::size_of::<B>(),
144 mem::size_of::<A>(),
145 "size mismatch in raw view cast"
146 );
147 let ptr = self.ptr.cast::<B>();
148 unsafe { RawArrayView::new(ptr, self.dim, self.strides) }
149 }
150}
151
152impl<A, D> RawArrayViewMut<A, D>
153where
154 D: Dimension,
155{
156 /// Create a new `RawArrayViewMut`.
157 ///
158 /// Unsafe because caller is responsible for ensuring that the array will
159 /// meet all of the invariants of the `ArrayBase` type.
160 #[inline]
161 pub(crate) unsafe fn new(ptr: NonNull<A>, dim: D, strides: D) -> Self {
162 RawArrayViewMut::from_data_ptr(RawViewRepr::new(), ptr)
163 .with_strides_dim(strides, dim)
164 }
165
166 unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self {
167 Self::new(nonnull_debug_checked_from_ptr(ptr), dim, strides)
168 }
169
170 /// Create an `RawArrayViewMut<A, D>` from shape information and a raw
171 /// pointer to the elements.
172 ///
173 /// # Safety
174 ///
175 /// The caller is responsible for ensuring all of the following:
176 ///
177 /// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
178 /// zero.
179 ///
180 /// * It must be safe to [`.offset()`] the pointer repeatedly along all
181 /// axes and calculate the `count`s for the `.offset()` calls without
182 /// overflow, even if the array is empty or the elements are zero-sized.
183 ///
184 /// In other words,
185 ///
186 /// * All possible pointers generated by moving along all axes must be in
187 /// bounds or one byte past the end of a single allocation with element
188 /// type `A`. The only exceptions are if the array is empty or the element
189 /// type is zero-sized. In these cases, `ptr` may be dangling, but it must
190 /// still be safe to [`.offset()`] the pointer along the axes.
191 ///
192 /// * The offset in units of bytes between the least address and greatest
193 /// address by moving along all axes must not exceed `isize::MAX`. This
194 /// constraint prevents the computed offset, in bytes, from overflowing
195 /// `isize` regardless of the starting point due to past offsets.
196 ///
197 /// * The offset in units of `A` between the least address and greatest
198 /// address by moving along all axes must not exceed `isize::MAX`. This
199 /// constraint prevents overflow when calculating the `count` parameter to
200 /// [`.offset()`] regardless of the starting point due to past offsets.
201 ///
202 /// * The product of non-zero axis lengths must not exceed `isize::MAX`.
203 ///
204 /// * Strides must be non-negative.
205 ///
206 /// This function can use debug assertions to check some of these requirements,
207 /// but it's not a complete check.
208 ///
209 /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
210 pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
211 where
212 Sh: Into<StrideShape<D>>,
213 {
214 let shape = shape.into();
215 let dim = shape.dim;
216 if cfg!(debug_assertions) {
217 assert!(!ptr.is_null(), "The pointer must be non-null.");
218 if let Strides::Custom(strides) = &shape.strides {
219 dimension::strides_non_negative(strides).unwrap();
220 dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
221 } else {
222 dimension::size_of_shape_checked(&dim).unwrap();
223 }
224 }
225 let strides = shape.strides.strides_for_dim(&dim);
226 RawArrayViewMut::new_(ptr, dim, strides)
227 }
228
229 /// Converts to a non-mutable `RawArrayView`.
230 #[inline]
231 pub(crate) fn into_raw_view(self) -> RawArrayView<A, D> {
232 unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) }
233 }
234
235 /// Converts to a read-only view of the array.
236 ///
237 /// # Safety
238 ///
239 /// From a safety standpoint, this is equivalent to dereferencing a raw
240 /// pointer for every element in the array. You must ensure that all of the
241 /// data is valid, ensure that the pointer is aligned, and choose the
242 /// correct lifetime.
243 #[inline]
244 pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
245 debug_assert!(
246 is_aligned(self.ptr.as_ptr()),
247 "The pointer must be aligned."
248 );
249 ArrayView::new(self.ptr, self.dim, self.strides)
250 }
251
252 /// Converts to a mutable view of the array.
253 ///
254 /// # Safety
255 ///
256 /// From a safety standpoint, this is equivalent to dereferencing a raw
257 /// pointer for every element in the array. You must ensure that all of the
258 /// data is valid, ensure that the pointer is aligned, and choose the
259 /// correct lifetime.
260 #[inline]
261 pub unsafe fn deref_into_view_mut<'a>(self) -> ArrayViewMut<'a, A, D> {
262 debug_assert!(
263 is_aligned(self.ptr.as_ptr()),
264 "The pointer must be aligned."
265 );
266 ArrayViewMut::new(self.ptr, self.dim, self.strides)
267 }
268
269 /// Split the array view along `axis` and return one array pointer strictly
270 /// before the split and one array pointer after the split.
271 ///
272 /// **Panics** if `axis` or `index` is out of bounds.
273 pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self) {
274 let (left, right) = self.into_raw_view().split_at(axis, index);
275 unsafe {
276 (
277 Self::new(left.ptr, left.dim, left.strides),
278 Self::new(right.ptr, right.dim, right.strides),
279 )
280 }
281 }
282
283 /// Cast the raw pointer of the raw array view to a different type
284 ///
285 /// **Panics** if element size is not compatible.
286 ///
287 /// Lack of panic does not imply it is a valid cast. The cast works the same
288 /// way as regular raw pointer casts.
289 ///
290 /// While this method is safe, for the same reason as regular raw pointer
291 /// casts are safe, access through the produced raw view is only possible
292 /// in an unsafe block or function.
293 pub fn cast<B>(self) -> RawArrayViewMut<B, D> {
294 assert_eq!(
295 mem::size_of::<B>(),
296 mem::size_of::<A>(),
297 "size mismatch in raw view cast"
298 );
299 let ptr = self.ptr.cast::<B>();
300 unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) }
301 }
302}