ndarray/
impl_raw_views.rs

1use num_complex::Complex;
2use std::mem;
3use std::ptr::NonNull;
4
5use crate::dimension::{self, stride_offset};
6use crate::extension::nonnull::nonnull_debug_checked_from_ptr;
7use crate::imp_prelude::*;
8use crate::is_aligned;
9use crate::shape_builder::{StrideShape, Strides};
10
11impl<A, D> RawArrayView<A, D>
12where 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    {
21        RawArrayView::from_data_ptr(RawViewRepr::new(), ptr).with_strides_dim(strides, dim)
22    }
23
24    #[inline]
25    unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self
26    {
27        Self::new(nonnull_debug_checked_from_ptr(ptr as *mut A), dim, strides)
28    }
29
30    /// Create an `RawArrayView<A, D>` from shape information and a raw pointer
31    /// to the elements.
32    ///
33    /// # Safety
34    ///
35    /// The caller is responsible for ensuring all of the following:
36    ///
37    /// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
38    ///   zero.
39    ///
40    /// * It must be safe to [`.offset()`] the pointer repeatedly along all
41    ///   axes and calculate the `count`s for the `.offset()` calls without
42    ///   overflow, even if the array is empty or the elements are zero-sized.
43    ///
44    ///   In other words,
45    ///
46    ///   * All possible pointers generated by moving along all axes must be in
47    ///     bounds or one byte past the end of a single allocation with element
48    ///     type `A`. The only exceptions are if the array is empty or the element
49    ///     type is zero-sized. In these cases, `ptr` may be dangling, but it must
50    ///     still be safe to [`.offset()`] the pointer along the axes.
51    ///
52    ///   * The offset in units of bytes between the least address and greatest
53    ///     address by moving along all axes must not exceed `isize::MAX`. This
54    ///     constraint prevents the computed offset, in bytes, from overflowing
55    ///     `isize` regardless of the starting point due to past offsets.
56    ///
57    ///   * The offset in units of `A` between the least address and greatest
58    ///     address by moving along all axes must not exceed `isize::MAX`. This
59    ///     constraint prevents overflow when calculating the `count` parameter to
60    ///     [`.offset()`] regardless of the starting point due to past offsets.
61    ///
62    /// * The product of non-zero axis lengths must not exceed `isize::MAX`.
63    ///
64    /// * Strides must be non-negative.
65    ///
66    /// This function can use debug assertions to check some of these requirements,
67    /// but it's not a complete check.
68    ///
69    /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
70    #[inline]
71    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
72    where Sh: Into<StrideShape<D>>
73    {
74        let shape = shape.into();
75        let dim = shape.dim;
76        if cfg!(debug_assertions) {
77            assert!(!ptr.is_null(), "The pointer must be non-null.");
78            if let Strides::Custom(strides) = &shape.strides {
79                dimension::strides_non_negative(strides).unwrap();
80                dimension::max_abs_offset_check_overflow::<A, _>(&dim, strides).unwrap();
81            } else {
82                dimension::size_of_shape_checked(&dim).unwrap();
83            }
84        }
85        let strides = shape.strides.strides_for_dim(&dim);
86        RawArrayView::new_(ptr, dim, strides)
87    }
88
89    /// Converts to a read-only view of the array.
90    ///
91    /// # Safety
92    ///
93    /// From a safety standpoint, this is equivalent to dereferencing a raw
94    /// pointer for every element in the array. You must ensure that all of the
95    /// data is valid, ensure that the pointer is aligned, and choose the
96    /// correct lifetime.
97    #[inline]
98    pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D>
99    {
100        debug_assert!(
101            is_aligned(self.ptr.as_ptr()),
102            "The pointer must be aligned."
103        );
104        ArrayView::new(self.ptr, self.dim, self.strides)
105    }
106
107    /// Split the array view along `axis` and return one array pointer strictly
108    /// before the split and one array pointer after the split.
109    ///
110    /// **Panics** if `axis` or `index` is out of bounds.
111    #[track_caller]
112    #[inline]
113    pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self)
114    {
115        assert!(index <= self.len_of(axis));
116        let left_ptr = self.ptr.as_ptr();
117        let right_ptr = if index == self.len_of(axis) {
118            self.ptr.as_ptr()
119        } else {
120            let offset = stride_offset(index, self.strides.axis(axis));
121            // The `.offset()` is safe due to the guarantees of `RawData`.
122            unsafe { self.ptr.as_ptr().offset(offset) }
123        };
124
125        let mut dim_left = self.dim.clone();
126        dim_left.set_axis(axis, index);
127        let left = unsafe { Self::new_(left_ptr, dim_left, self.strides.clone()) };
128
129        let mut dim_right = self.dim;
130        let right_len = dim_right.axis(axis) - index;
131        dim_right.set_axis(axis, right_len);
132        let right = unsafe { Self::new_(right_ptr, dim_right, self.strides) };
133
134        (left, right)
135    }
136
137    /// Cast the raw pointer of the raw array view to a different type
138    ///
139    /// **Panics** if element size is not compatible.
140    ///
141    /// Lack of panic does not imply it is a valid cast. The cast works the same
142    /// way as regular raw pointer casts.
143    ///
144    /// While this method is safe, for the same reason as regular raw pointer
145    /// casts are safe, access through the produced raw view is only possible
146    /// in an unsafe block or function.
147    #[track_caller]
148    pub fn cast<B>(self) -> RawArrayView<B, D>
149    {
150        assert_eq!(
151            mem::size_of::<B>(),
152            mem::size_of::<A>(),
153            "size mismatch in raw view cast"
154        );
155        let ptr = self.ptr.cast::<B>();
156        unsafe { RawArrayView::new(ptr, self.dim, self.strides) }
157    }
158}
159
160impl<T, D> RawArrayView<Complex<T>, D>
161where D: Dimension
162{
163    /// Splits the view into views of the real and imaginary components of the
164    /// elements.
165    pub fn split_complex(self) -> Complex<RawArrayView<T, D>>
166    {
167        // Check that the size and alignment of `Complex<T>` are as expected.
168        // These assertions should always pass, for arbitrary `T`.
169        assert_eq!(
170            mem::size_of::<Complex<T>>(),
171            mem::size_of::<T>().checked_mul(2).unwrap()
172        );
173        assert_eq!(mem::align_of::<Complex<T>>(), mem::align_of::<T>());
174
175        let dim = self.dim.clone();
176
177        // Double the strides. In the zero-sized element case and for axes of
178        // length <= 1, we leave the strides as-is to avoid possible overflow.
179        let mut strides = self.strides.clone();
180        if mem::size_of::<T>() != 0 {
181            for ax in 0..strides.ndim() {
182                if dim[ax] > 1 {
183                    strides[ax] = (strides[ax] as isize * 2) as usize;
184                }
185            }
186        }
187
188        let ptr_re: *mut T = self.ptr.as_ptr().cast();
189        let ptr_im: *mut T = if self.is_empty() {
190            // In the empty case, we can just reuse the existing pointer since
191            // it won't be dereferenced anyway. It is not safe to offset by
192            // one, since the allocation may be empty.
193            ptr_re
194        } else {
195            // In the nonempty case, we can safely offset into the first
196            // (complex) element.
197            unsafe { ptr_re.add(1) }
198        };
199
200        // `Complex` is `repr(C)` with only fields `re: T` and `im: T`. So, the
201        // real components of the elements start at the same pointer, and the
202        // imaginary components start at the pointer offset by one, with
203        // exactly double the strides. The new, doubled strides still meet the
204        // overflow constraints:
205        //
206        // - For the zero-sized element case, the strides are unchanged in
207        //   units of bytes and in units of the element type.
208        //
209        // - For the nonzero-sized element case:
210        //
211        //   - In units of bytes, the strides are unchanged. The only exception
212        //     is axes of length <= 1, but those strides are irrelevant anyway.
213        //
214        //   - Since `Complex<T>` for nonzero `T` is always at least 2 bytes,
215        //     and the original strides did not overflow in units of bytes, we
216        //     know that the new, doubled strides will not overflow in units of
217        //     `T`.
218        unsafe {
219            Complex {
220                re: RawArrayView::new_(ptr_re, dim.clone(), strides.clone()),
221                im: RawArrayView::new_(ptr_im, dim, strides),
222            }
223        }
224    }
225}
226
227impl<A, D> RawArrayViewMut<A, D>
228where D: Dimension
229{
230    /// Create a new `RawArrayViewMut`.
231    ///
232    /// Unsafe because caller is responsible for ensuring that the array will
233    /// meet all of the invariants of the `ArrayBase` type.
234    #[inline]
235    pub(crate) unsafe fn new(ptr: NonNull<A>, dim: D, strides: D) -> Self
236    {
237        RawArrayViewMut::from_data_ptr(RawViewRepr::new(), ptr).with_strides_dim(strides, dim)
238    }
239
240    #[inline]
241    unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self
242    {
243        Self::new(nonnull_debug_checked_from_ptr(ptr), dim, strides)
244    }
245
246    /// Create an `RawArrayViewMut<A, D>` from shape information and a raw
247    /// pointer to the elements.
248    ///
249    /// # Safety
250    ///
251    /// The caller is responsible for ensuring all of the following:
252    ///
253    /// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
254    ///   zero.
255    ///
256    /// * It must be safe to [`.offset()`] the pointer repeatedly along all
257    ///   axes and calculate the `count`s for the `.offset()` calls without
258    ///   overflow, even if the array is empty or the elements are zero-sized.
259    ///
260    ///   In other words,
261    ///
262    ///   * All possible pointers generated by moving along all axes must be in
263    ///     bounds or one byte past the end of a single allocation with element
264    ///     type `A`. The only exceptions are if the array is empty or the element
265    ///     type is zero-sized. In these cases, `ptr` may be dangling, but it must
266    ///     still be safe to [`.offset()`] the pointer along the axes.
267    ///
268    ///   * The offset in units of bytes between the least address and greatest
269    ///     address by moving along all axes must not exceed `isize::MAX`. This
270    ///     constraint prevents the computed offset, in bytes, from overflowing
271    ///     `isize` regardless of the starting point due to past offsets.
272    ///
273    ///   * The offset in units of `A` between the least address and greatest
274    ///     address by moving along all axes must not exceed `isize::MAX`. This
275    ///     constraint prevents overflow when calculating the `count` parameter to
276    ///     [`.offset()`] regardless of the starting point due to past offsets.
277    ///
278    /// * The product of non-zero axis lengths must not exceed `isize::MAX`.
279    ///
280    /// * Strides must be non-negative.
281    ///
282    /// This function can use debug assertions to check some of these requirements,
283    /// but it's not a complete check.
284    ///
285    /// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
286    #[inline]
287    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
288    where Sh: Into<StrideShape<D>>
289    {
290        let shape = shape.into();
291        let dim = shape.dim;
292        if cfg!(debug_assertions) {
293            assert!(!ptr.is_null(), "The pointer must be non-null.");
294            if let Strides::Custom(strides) = &shape.strides {
295                dimension::strides_non_negative(strides).unwrap();
296                dimension::max_abs_offset_check_overflow::<A, _>(&dim, strides).unwrap();
297                assert!(!dimension::dim_stride_overlap(&dim, strides),
298                        "The strides must not allow any element to be referenced by two different indices");
299            } else {
300                dimension::size_of_shape_checked(&dim).unwrap();
301            }
302        }
303        let strides = shape.strides.strides_for_dim(&dim);
304        RawArrayViewMut::new_(ptr, dim, strides)
305    }
306
307    /// Converts to a non-mutable `RawArrayView`.
308    #[inline]
309    pub(crate) fn into_raw_view(self) -> RawArrayView<A, D>
310    {
311        unsafe { RawArrayView::new(self.ptr, self.dim, self.strides) }
312    }
313
314    /// Converts to a read-only view of the array.
315    ///
316    /// # Safety
317    ///
318    /// From a safety standpoint, this is equivalent to dereferencing a raw
319    /// pointer for every element in the array. You must ensure that all of the
320    /// data is valid, ensure that the pointer is aligned, and choose the
321    /// correct lifetime.
322    #[inline]
323    pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D>
324    {
325        debug_assert!(
326            is_aligned(self.ptr.as_ptr()),
327            "The pointer must be aligned."
328        );
329        ArrayView::new(self.ptr, self.dim, self.strides)
330    }
331
332    /// Converts to a mutable view of the array.
333    ///
334    /// # Safety
335    ///
336    /// From a safety standpoint, this is equivalent to dereferencing a raw
337    /// pointer for every element in the array. You must ensure that all of the
338    /// data is valid, ensure that the pointer is aligned, and choose the
339    /// correct lifetime.
340    #[inline]
341    pub unsafe fn deref_into_view_mut<'a>(self) -> ArrayViewMut<'a, A, D>
342    {
343        debug_assert!(
344            is_aligned(self.ptr.as_ptr()),
345            "The pointer must be aligned."
346        );
347        ArrayViewMut::new(self.ptr, self.dim, self.strides)
348    }
349
350    /// Split the array view along `axis` and return one array pointer strictly
351    /// before the split and one array pointer after the split.
352    ///
353    /// **Panics** if `axis` or `index` is out of bounds.
354    #[track_caller]
355    #[inline]
356    pub fn split_at(self, axis: Axis, index: Ix) -> (Self, Self)
357    {
358        let (left, right) = self.into_raw_view().split_at(axis, index);
359        unsafe { (Self::new(left.ptr, left.dim, left.strides), Self::new(right.ptr, right.dim, right.strides)) }
360    }
361
362    /// Cast the raw pointer of the raw array view to a different type
363    ///
364    /// **Panics** if element size is not compatible.
365    ///
366    /// Lack of panic does not imply it is a valid cast. The cast works the same
367    /// way as regular raw pointer casts.
368    ///
369    /// While this method is safe, for the same reason as regular raw pointer
370    /// casts are safe, access through the produced raw view is only possible
371    /// in an unsafe block or function.
372    #[track_caller]
373    pub fn cast<B>(self) -> RawArrayViewMut<B, D>
374    {
375        assert_eq!(
376            mem::size_of::<B>(),
377            mem::size_of::<A>(),
378            "size mismatch in raw view cast"
379        );
380        let ptr = self.ptr.cast::<B>();
381        unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) }
382    }
383}
384
385impl<T, D> RawArrayViewMut<Complex<T>, D>
386where D: Dimension
387{
388    /// Splits the view into views of the real and imaginary components of the
389    /// elements.
390    pub fn split_complex(self) -> Complex<RawArrayViewMut<T, D>>
391    {
392        let Complex { re, im } = self.into_raw_view().split_complex();
393        unsafe {
394            Complex {
395                re: RawArrayViewMut::new(re.ptr, re.dim, re.strides),
396                im: RawArrayViewMut::new(im.ptr, im.dim, im.strides),
397            }
398        }
399    }
400}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy