Skip to content

Commit ba50d0d

Browse files
authored
Merge pull request #350 from bluss/bounds-check-elim
Tweak bounds checked indexing code (Index, IndexMut)
2 parents 5b4c04e + 4f5c305 commit ba50d0d

File tree

3 files changed

+146
-2
lines changed

3 files changed

+146
-2
lines changed

examples/bounds_check_elim.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#![crate_type="lib"]
2+
3+
// Test cases for bounds check elimination
4+
5+
extern crate ndarray;
6+
7+
use ndarray::prelude::*;
8+
9+
/*
10+
pub fn testslice(a: &[f64]) -> f64 {
11+
let mut sum = 0.;
12+
for i in 0..a.len() {
13+
sum += a[i];
14+
}
15+
sum
16+
}
17+
18+
pub fn testvec(a: &Vec<f64>) -> f64 {
19+
let mut sum = 0.;
20+
for i in 0..a.len() {
21+
sum += a[i];
22+
}
23+
sum
24+
}
25+
26+
pub fn testvec_as_slice(a: &Vec<f64>) -> f64 {
27+
let a = a.as_slice();
28+
let mut sum = 0.;
29+
for i in 0..a.len() {
30+
sum += a[i];
31+
}
32+
sum
33+
}
34+
*/
35+
36+
#[no_mangle]
37+
pub fn test1d_single(a: &Array1<f64>, i: usize) -> f64 {
38+
if i < a.len() { a[i] } else { 0. }
39+
}
40+
41+
#[no_mangle]
42+
pub fn test1d_single_mut(a: &mut Array1<f64>, i: usize) -> f64 {
43+
if i < a.len() { *&mut a[i] } else { 0. }
44+
}
45+
46+
#[no_mangle]
47+
pub fn test1d_len_of(a: &Array1<f64>) -> f64 {
48+
let a = &*a;
49+
let mut sum = 0.;
50+
for i in 0..a.len_of(Axis(0)) {
51+
sum += a[i];
52+
}
53+
sum
54+
}
55+
56+
#[no_mangle]
57+
pub fn test1d_range(a: &Array1<f64>) -> f64 {
58+
let mut sum = 0.;
59+
for i in 0..a.len() {
60+
sum += a[i];
61+
}
62+
sum
63+
}
64+
65+
#[no_mangle]
66+
pub fn test1d_while(a: &Array1<f64>) -> f64 {
67+
let mut sum = 0.;
68+
let mut i = 0;
69+
while i < a.len() {
70+
sum += a[i];
71+
i += 1;
72+
}
73+
sum
74+
}
75+
76+
#[no_mangle]
77+
pub fn test2d_ranges(a: &Array2<f64>) -> f64 {
78+
let mut sum = 0.;
79+
for i in 0..a.rows() {
80+
for j in 0..a.cols() {
81+
sum += a[[i, j]];
82+
}
83+
}
84+
sum
85+
}
86+
87+
#[no_mangle]
88+
pub fn test2d_whiles(a: &Array2<f64>) -> f64 {
89+
let mut sum = 0.;
90+
let mut i = 0;
91+
while i < a.rows() {
92+
let mut j = 0;
93+
while j < a.cols() {
94+
sum += a[[i, j]];
95+
j += 1;
96+
}
97+
i += 1;
98+
}
99+
sum
100+
}
101+
102+
fn main() {
103+
}

src/arraytraits.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ impl<S, D, I> Index<I> for ArrayBase<S, D>
6969
#[inline]
7070
fn index(&self, index: I) -> &S::Elem {
7171
debug_bounds_check!(self, index);
72-
self.get(index).unwrap_or_else(|| array_out_of_bounds())
72+
unsafe {
73+
&*self.ptr.offset(index.index_checked(&self.dim, &self.strides)
74+
.unwrap_or_else(|| array_out_of_bounds()))
75+
}
7376
}
7477
}
7578

@@ -84,7 +87,10 @@ impl<S, D, I> IndexMut<I> for ArrayBase<S, D>
8487
#[inline]
8588
fn index_mut(&mut self, index: I) -> &mut S::Elem {
8689
debug_bounds_check!(self, index);
87-
self.get_mut(index).unwrap_or_else(|| array_out_of_bounds())
90+
unsafe {
91+
&mut *self.as_mut_ptr().offset(index.index_checked(&self.dim, &self.strides)
92+
.unwrap_or_else(|| array_out_of_bounds()))
93+
}
8894
}
8995
}
9096

tests/array.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,41 @@ fn test_cow()
219219
assert_eq!(before[3], 1);
220220
}
221221

222+
#[test]
223+
fn test_cow_shrink()
224+
{
225+
// A test for clone-on-write in the case that
226+
// mutation shrinks the array and gives it different strides
227+
//
228+
let mut mat = RcArray::zeros((2, 3));
229+
//mat.islice(s![.., ..;2]);
230+
mat[[0, 0]] = 1;
231+
let n = mat.clone();
232+
mat[[0, 1]] = 2;
233+
mat[[0, 2]] = 3;
234+
mat[[1, 0]] = 4;
235+
mat[[1, 1]] = 5;
236+
mat[[1, 2]] = 6;
237+
assert_eq!(mat[[0, 0]], 1);
238+
assert_eq!(mat[[0, 1]], 2);
239+
assert_eq!(n[[0, 0]], 1);
240+
assert_eq!(n[[0, 1]], 0);
241+
assert_eq!(n.get((0, 1)), Some(&0));
242+
// small has non-C strides this way
243+
let mut small = mat.reshape(6);
244+
small.islice(s![4..;-1]);
245+
assert_eq!(small[0], 6);
246+
assert_eq!(small[1], 5);
247+
let before = small.clone();
248+
// mutation
249+
// small gets back C strides in CoW.
250+
small[1] = 9;
251+
assert_eq!(small[0], 6);
252+
assert_eq!(small[1], 9);
253+
assert_eq!(before[0], 6);
254+
assert_eq!(before[1], 5);
255+
}
256+
222257
#[test]
223258
fn test_sub()
224259
{

0 commit comments

Comments
 (0)