Skip to content

Commit bd6d077

Browse files
committed
BUG: Fix safety of unchecked elem methods and move them all to the right file
Unchecked indexing is `unsafe`.
1 parent 4b75206 commit bd6d077

File tree

3 files changed

+74
-74
lines changed

3 files changed

+74
-74
lines changed

src/arraytraits.rs

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,10 @@ use {Zip, FoldWhile};
2828

2929
#[cold]
3030
#[inline(never)]
31-
fn array_out_of_bounds() -> ! {
31+
pub(crate) fn array_out_of_bounds() -> ! {
3232
panic!("ndarray: index out of bounds");
3333
}
3434

35-
// Macro to insert more informative out of bounds message in debug builds
36-
#[cfg(debug_assertions)]
37-
macro_rules! debug_bounds_check {
38-
($self_:ident, $index:expr) => {
39-
if let None = $index.index_checked(&$self_.dim, &$self_.strides) {
40-
panic!("ndarray: index {:?} is out of bounds for array of shape {:?}",
41-
$index, $self_.shape());
42-
}
43-
};
44-
}
45-
46-
#[cfg(not(debug_assertions))]
47-
macro_rules! debug_bounds_check {
48-
($self_:ident, $index:expr) => { };
49-
}
50-
5135
#[inline(always)]
5236
pub fn debug_bounds_check<S, D, I>(_a: &ArrayBase<S, D>, _index: &I)
5337
where D: Dimension,
@@ -94,62 +78,6 @@ impl<S, D, I> IndexMut<I> for ArrayBase<S, D>
9478
}
9579
}
9680

97-
impl<'a, A, D> ArrayView<'a, A, D>
98-
where
99-
D: Dimension,
100-
{
101-
/// Get a reference of a element through the view.
102-
///
103-
/// This is a replacement of `Index::index` since it forces us a wrong lifetime
104-
/// https://github.com/bluss/rust-ndarray/issues/371
105-
pub fn elem<I: NdIndex<D>>(&self, index: I) -> &'a A {
106-
debug_bounds_check!(self, index);
107-
unsafe {
108-
&*self.as_ptr().offset(
109-
index
110-
.index_checked(&self.dim, &self.strides)
111-
.unwrap_or_else(|| array_out_of_bounds()),
112-
)
113-
}
114-
}
115-
116-
/// Get a reference of a element through the view without boundary check
117-
///
118-
/// This is a replacement of `Index::index` since it forces us a wrong lifetime
119-
/// https://github.com/bluss/rust-ndarray/issues/371
120-
pub fn uelem<I: NdIndex<D>>(&self, index: I) -> &'a A {
121-
debug_bounds_check!(self, index);
122-
unsafe { &*self.as_ptr().offset(index.index_unchecked(&self.strides)) }
123-
}
124-
}
125-
126-
impl<'a, A, D> ArrayViewMut<'a, A, D>
127-
where
128-
D: Dimension,
129-
{
130-
/// Convert a mutable array view to a mutable reference of a element.
131-
pub fn into_elem<I: NdIndex<D>>(mut self, index: I) -> &'a mut A {
132-
debug_bounds_check!(self, index);
133-
unsafe {
134-
&mut *self.as_mut_ptr().offset(
135-
index
136-
.index_checked(&self.dim, &self.strides)
137-
.unwrap_or_else(|| array_out_of_bounds()),
138-
)
139-
}
140-
}
141-
142-
/// Convert a mutable array view to a mutable reference of a element without boundary check
143-
pub fn into_elem_unchecked<I: NdIndex<D>>(mut self, index: I) -> &'a mut A {
144-
debug_bounds_check!(self, index);
145-
unsafe {
146-
&mut *self.as_mut_ptr().offset(
147-
index.index_unchecked(&self.strides),
148-
)
149-
}
150-
}
151-
}
152-
15381
/// Return `true` if the array shapes and all elements of `self` and
15482
/// `rhs` are equal. Return `false` otherwise.
15583
impl<S, S2, D> PartialEq<ArrayBase<S2, D>> for ArrayBase<S, D>

src/impl_views.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use std::slice;
1111
use imp_prelude::*;
1212
use dimension::{self, stride_offset};
1313
use error::ShapeError;
14-
14+
use NdIndex;
15+
use arraytraits::array_out_of_bounds;
1516
use StrideShape;
1617

1718
use {
@@ -133,6 +134,33 @@ impl<'a, A, D> ArrayView<'a, A, D>
133134
}
134135
}
135136

137+
/// Get a reference of a element through the view.
138+
///
139+
/// This method is like `Index::index` but with a longer lifetime (matching
140+
/// the array view); which we can't do for general arrays and not in the
141+
/// `Index` trait.
142+
pub fn elem<I>(&self, index: I) -> &'a A
143+
where I: NdIndex<D>,
144+
{
145+
debug_bounds_check!(self, index);
146+
unsafe {
147+
&*self.as_ptr().offset(index
148+
.index_checked(&self.dim, &self.strides)
149+
.unwrap_or_else(|| array_out_of_bounds()))
150+
}
151+
}
152+
153+
/// Get a reference of a element through the view without boundary check
154+
///
155+
/// This method is like `elem` with a longer lifetime (matching the array
156+
/// view); which we can't do for general arrays.
157+
pub unsafe fn uelem<I>(&self, index: I) -> &'a A
158+
where I: NdIndex<D>,
159+
{
160+
debug_bounds_check!(self, index);
161+
&*self.as_ptr().offset(index.index_unchecked(&self.strides))
162+
}
163+
136164
}
137165

138166
/// Methods for read-write array views.
@@ -233,6 +261,33 @@ impl<'a, A, D> ArrayViewMut<'a, A, D>
233261
self.into_slice_().ok()
234262
}
235263

264+
/// Convert a mutable array view to a mutable reference of a element.
265+
///
266+
/// This method is like `Index::index` but with a longer lifetime (matching
267+
/// the array view); which we can't do for general arrays and not in the
268+
/// `Index` trait.
269+
pub fn into_elem<I>(mut self, index: I) -> &'a mut A
270+
where I: NdIndex<D>,
271+
{
272+
debug_bounds_check!(self, index);
273+
unsafe {
274+
&mut *self.as_mut_ptr().offset(
275+
index
276+
.index_checked(&self.dim, &self.strides)
277+
.unwrap_or_else(|| array_out_of_bounds()),
278+
)
279+
}
280+
}
281+
282+
/// Convert a mutable array view to a mutable reference of a element without boundary check
283+
///
284+
///
285+
pub unsafe fn into_elem_unchecked<I>(mut self, index: I) -> &'a mut A
286+
where I: NdIndex<D>
287+
{
288+
debug_bounds_check!(self, index);
289+
&mut *self.as_mut_ptr().offset(index.index_unchecked(&self.strides))
290+
}
236291
}
237292

238293
/// Private array view methods

src/macro_utils.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,20 @@ macro_rules! expand_if {
5555
};
5656
(@nonempty [] $($body:tt)*) => { };
5757
}
58+
59+
// Macro to insert more informative out of bounds message in debug builds
60+
#[cfg(debug_assertions)]
61+
macro_rules! debug_bounds_check {
62+
($self_:ident, $index:expr) => {
63+
if let None = $index.index_checked(&$self_.dim, &$self_.strides) {
64+
panic!("ndarray: index {:?} is out of bounds for array of shape {:?}",
65+
$index, $self_.shape());
66+
}
67+
};
68+
}
69+
70+
#[cfg(not(debug_assertions))]
71+
macro_rules! debug_bounds_check {
72+
($self_:ident, $index:expr) => { };
73+
}
74+

0 commit comments

Comments
 (0)