Skip to content

Commit 8e6a936

Browse files
committed
Add conversions to/from RawArrayView(Mut)
1 parent 619f737 commit 8e6a936

File tree

4 files changed

+234
-7
lines changed

4 files changed

+234
-7
lines changed

src/impl_methods.rs

+28
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,19 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
10681068
}
10691069
}
10701070

1071+
/// Try to make the array unshared.
1072+
///
1073+
/// This is equivalent to `.ensure_unique()` if `S: DataMut`.
1074+
///
1075+
/// This method is mostly only useful with unsafe code.
1076+
fn try_ensure_unique(&mut self)
1077+
where S: DataRawMut
1078+
{
1079+
debug_assert!(self.pointer_is_inbounds());
1080+
S::try_ensure_unique(self);
1081+
debug_assert!(self.pointer_is_inbounds());
1082+
}
1083+
10711084
/// Make the array unshared.
10721085
///
10731086
/// This method is mostly only useful with unsafe code.
@@ -1128,6 +1141,21 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
11281141
self.ptr
11291142
}
11301143

1144+
/// Return a raw view of the array.
1145+
#[inline]
1146+
pub fn raw_view(&self) -> RawArrayView<A, D> {
1147+
unsafe { RawArrayView::new_(self.ptr, self.dim.clone(), self.strides.clone()) }
1148+
}
1149+
1150+
/// Return a raw mutable view of the array.
1151+
#[inline]
1152+
pub fn raw_view_mut(&mut self) -> RawArrayViewMut<A, D>
1153+
where S: DataRawMut
1154+
{
1155+
self.try_ensure_unique(); // for RcArray
1156+
unsafe { RawArrayViewMut::new_(self.ptr, self.dim.clone(), self.strides.clone()) }
1157+
}
1158+
11311159
/// Return the array’s data as a slice, if it is contiguous and in standard order.
11321160
/// Return `None` otherwise.
11331161
///

src/impl_raw_views.rs

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
use dimension;
2+
use imp_prelude::*;
3+
use {is_aligned, StrideShape};
4+
5+
impl<A, D> RawArrayView<A, D>
6+
where
7+
D: Dimension,
8+
{
9+
/// Create a new `RawArrayView`.
10+
///
11+
/// Unsafe because caller is responsible for ensuring that the array will
12+
/// meet all of the invariants of the `ArrayBase` type.
13+
#[inline(always)]
14+
pub(crate) unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self {
15+
RawArrayView {
16+
data: RawViewRepr::new(),
17+
ptr: ptr as *mut A,
18+
dim: dim,
19+
strides: strides,
20+
}
21+
}
22+
23+
/// Create an `RawArrayView<A, D>` from shape information and a raw pointer
24+
/// to the elements.
25+
///
26+
/// Unsafe because caller is responsible for ensuring all of the following:
27+
///
28+
/// * `ptr` must be non-null and aligned, and it must be safe to
29+
/// [`.offset()`] `ptr` by zero.
30+
///
31+
/// * It must be safe to [`.offset()`] the pointer repeatedly along all
32+
/// axes and calculate the `count`s for the `.offset()` calls without
33+
/// overflow, even if the array is empty or the elements are zero-sized.
34+
///
35+
/// In other words,
36+
///
37+
/// * All possible pointers generated by moving along all axes must be in
38+
/// bounds or one byte past the end of a single allocation with element
39+
/// type `A`. The only exceptions are if the array is empty or the element
40+
/// type is zero-sized. In these cases, `ptr` may be dangling, but it must
41+
/// still be safe to [`.offset()`] the pointer along the axes.
42+
///
43+
/// * The offset in units of bytes between the least address and greatest
44+
/// address by moving along all axes must not exceed `isize::MAX`. This
45+
/// constraint prevents the computed offset, in bytes, from overflowing
46+
/// `isize` regardless of the starting point due to past offsets.
47+
///
48+
/// * The offset in units of `A` between the least address and greatest
49+
/// address by moving along all axes must not exceed `isize::MAX`. This
50+
/// constraint prevents overflow when calculating the `count` parameter to
51+
/// [`.offset()`] regardless of the starting point due to past offsets.
52+
///
53+
/// * The product of non-zero axis lengths must not exceed `isize::MAX`.
54+
///
55+
/// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
56+
pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
57+
where
58+
Sh: Into<StrideShape<D>>,
59+
{
60+
let shape = shape.into();
61+
let dim = shape.dim;
62+
let strides = shape.strides;
63+
if cfg!(debug_assertions) {
64+
assert!(!ptr.is_null(), "The pointer must be non-null.");
65+
assert!(is_aligned(ptr), "The pointer must be aligned.");
66+
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
67+
}
68+
RawArrayView::new_(ptr, dim, strides)
69+
}
70+
71+
/// Return a read-only view of the array.
72+
///
73+
/// **Warning** from a safety standpoint, this is equivalent to
74+
/// dereferencing a raw pointer for every element in the array. You must
75+
/// ensure that all of the data is valid and choose the correct lifetime.
76+
#[inline]
77+
pub unsafe fn deref_view<'a>(&self) -> ArrayView<'a, A, D> {
78+
ArrayView::new_(self.ptr, self.dim.clone(), self.strides.clone())
79+
}
80+
81+
/// Converts to a read-only view of the array.
82+
///
83+
/// **Warning** from a safety standpoint, this is equivalent to
84+
/// dereferencing a raw pointer for every element in the array. You must
85+
/// ensure that all of the data is valid and choose the correct lifetime.
86+
#[inline]
87+
pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
88+
ArrayView::new_(self.ptr, self.dim, self.strides)
89+
}
90+
}
91+
92+
impl<A, D> RawArrayViewMut<A, D>
93+
where
94+
D: Dimension,
95+
{
96+
/// Create a new `RawArrayViewMut`.
97+
///
98+
/// Unsafe because caller is responsible for ensuring that the array will
99+
/// meet all of the invariants of the `ArrayBase` type.
100+
#[inline(always)]
101+
pub(crate) unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self {
102+
RawArrayViewMut {
103+
data: RawViewRepr::new(),
104+
ptr: ptr,
105+
dim: dim,
106+
strides: strides,
107+
}
108+
}
109+
110+
/// Create an `RawArrayViewMut<A, D>` from shape information and a raw
111+
/// pointer to the elements.
112+
///
113+
/// Unsafe because caller is responsible for ensuring all of the following:
114+
///
115+
/// * `ptr` must be non-null and aligned, and it must be safe to
116+
/// [`.offset()`] `ptr` by zero.
117+
///
118+
/// * It must be safe to [`.offset()`] the pointer repeatedly along all
119+
/// axes and calculate the `count`s for the `.offset()` calls without
120+
/// overflow, even if the array is empty or the elements are zero-sized.
121+
///
122+
/// In other words,
123+
///
124+
/// * All possible pointers generated by moving along all axes must be in
125+
/// bounds or one byte past the end of a single allocation with element
126+
/// type `A`. The only exceptions are if the array is empty or the element
127+
/// type is zero-sized. In these cases, `ptr` may be dangling, but it must
128+
/// still be safe to [`.offset()`] the pointer along the axes.
129+
///
130+
/// * The offset in units of bytes between the least address and greatest
131+
/// address by moving along all axes must not exceed `isize::MAX`. This
132+
/// constraint prevents the computed offset, in bytes, from overflowing
133+
/// `isize` regardless of the starting point due to past offsets.
134+
///
135+
/// * The offset in units of `A` between the least address and greatest
136+
/// address by moving along all axes must not exceed `isize::MAX`. This
137+
/// constraint prevents overflow when calculating the `count` parameter to
138+
/// [`.offset()`] regardless of the starting point due to past offsets.
139+
///
140+
/// * The product of non-zero axis lengths must not exceed `isize::MAX`.
141+
///
142+
/// [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
143+
pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
144+
where
145+
Sh: Into<StrideShape<D>>,
146+
{
147+
let shape = shape.into();
148+
let dim = shape.dim;
149+
let strides = shape.strides;
150+
if cfg!(debug_assertions) {
151+
assert!(!ptr.is_null(), "The pointer must be non-null.");
152+
assert!(is_aligned(ptr), "The pointer must be aligned.");
153+
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
154+
}
155+
RawArrayViewMut::new_(ptr, dim, strides)
156+
}
157+
158+
/// Return a read-only view of the array
159+
///
160+
/// **Warning** from a safety standpoint, this is equivalent to
161+
/// dereferencing a raw pointer for every element in the array. You must
162+
/// ensure that all of the data is valid and choose the correct lifetime.
163+
#[inline]
164+
pub unsafe fn deref_view<'a>(&self) -> ArrayView<'a, A, D> {
165+
ArrayView::new_(self.ptr, self.dim.clone(), self.strides.clone())
166+
}
167+
168+
/// Return a read-write view of the array
169+
///
170+
/// **Warning** from a safety standpoint, this is equivalent to
171+
/// dereferencing a raw pointer for every element in the array. You must
172+
/// ensure that all of the data is valid and choose the correct lifetime.
173+
#[inline]
174+
pub unsafe fn deref_view_mut<'a>(&mut self) -> ArrayViewMut<'a, A, D> {
175+
ArrayViewMut::new_(self.ptr, self.dim.clone(), self.strides.clone())
176+
}
177+
178+
/// Converts to a read-only view of the array.
179+
///
180+
/// **Warning** from a safety standpoint, this is equivalent to
181+
/// dereferencing a raw pointer for every element in the array. You must
182+
/// ensure that all of the data is valid and choose the correct lifetime.
183+
#[inline]
184+
pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
185+
ArrayView::new_(self.ptr, self.dim, self.strides)
186+
}
187+
188+
/// Converts to a mutable view of the array.
189+
///
190+
/// **Warning** from a safety standpoint, this is equivalent to
191+
/// dereferencing a raw pointer for every element in the array. You must
192+
/// ensure that all of the data is valid and choose the correct lifetime.
193+
#[inline]
194+
pub unsafe fn deref_into_view_mut<'a>(self) -> ArrayViewMut<'a, A, D> {
195+
ArrayViewMut::new_(self.ptr, self.dim, self.strides)
196+
}
197+
}

src/impl_views.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ use std::slice;
1111
use imp_prelude::*;
1212
use dimension::{self, stride_offset};
1313
use error::ShapeError;
14-
use NdIndex;
1514
use arraytraits::array_out_of_bounds;
16-
use StrideShape;
15+
use {is_aligned, NdIndex, StrideShape};
1716

1817
use {
1918
ElementsBase,
@@ -25,11 +24,6 @@ use {
2524

2625
use iter::{self, AxisIter, AxisIterMut};
2726

28-
/// Returns `true` if the pointer is aligned.
29-
fn is_aligned<T>(ptr: *const T) -> bool {
30-
(ptr as usize) % ::std::mem::align_of::<T>() == 0
31-
}
32-
3327
/// Methods for read-only array views.
3428
impl<'a, A, D> ArrayView<'a, A, D>
3529
where D: Dimension,

src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,9 @@ pub use impl_ops::ScalarOperand;
13551355
// Array view methods
13561356
mod impl_views;
13571357

1358+
// Array raw view methods
1359+
mod impl_raw_views;
1360+
13581361
/// A contiguous array shape of n dimensions.
13591362
///
13601363
/// Either c- or f- memory ordered (*c* a.k.a *row major* is the default).
@@ -1371,3 +1374,8 @@ pub struct StrideShape<D> {
13711374
strides: D,
13721375
custom: bool,
13731376
}
1377+
1378+
/// Returns `true` if the pointer is aligned.
1379+
pub(crate) fn is_aligned<T>(ptr: *const T) -> bool {
1380+
(ptr as usize) % ::std::mem::align_of::<T>() == 0
1381+
}

0 commit comments

Comments
 (0)