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}